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 32244 : 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 32244 : const_TokenPtr tok = lexer.peek_token ();
75 32244 : switch (tok->get_id ())
76 : {
77 28253 : case RIGHT_ANGLE:
78 : // this is good - skip token
79 28253 : lexer.skip_token ();
80 28253 : return true;
81 3990 : case RIGHT_SHIFT:
82 : {
83 : // new implementation that should be better
84 3990 : lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE);
85 3990 : lexer.skip_token ();
86 3990 : 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 32244 : }
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 894871 : Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
118 : {
119 : // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
120 894871 : 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 51669 : case DOT:
149 103338 : if (lexer.peek_token (1)->get_id () == IDENTIFIER
150 94265 : && 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 10844 : case AS:
167 10844 : 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 748 : case OR:
215 748 : 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 781128 : default:
255 781128 : 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 5527 : Parser<ManagedTokenSource>::parse_items ()
272 : {
273 5527 : std::vector<std::unique_ptr<AST::Item>> items;
274 :
275 5527 : const_TokenPtr t = lexer.peek_token ();
276 33479 : while (t->get_id () != END_OF_FILE)
277 : {
278 27952 : auto item = parse_item (false);
279 27952 : if (!item)
280 84 : return Parse::Error::Items::make_malformed (std::move (items));
281 :
282 27868 : items.push_back (std::move (item.value ()));
283 :
284 27868 : 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 5443 : return items;
292 : #endif
293 5527 : }
294 :
295 : // Parses a crate (compilation unit) - entry point
296 : template <typename ManagedTokenSource>
297 : std::unique_ptr<AST::Crate>
298 5238 : Parser<ManagedTokenSource>::parse_crate ()
299 : {
300 : // parse inner attributes
301 5238 : AST::AttrVec inner_attrs = parse_inner_attributes ();
302 :
303 : // parse items
304 10476 : auto items
305 5238 : = parse_items ().value_or (std::vector<std::unique_ptr<AST::Item>>{});
306 :
307 : // emit all errors
308 5423 : for (const auto &error : error_table)
309 185 : error.emit ();
310 :
311 : return std::unique_ptr<AST::Crate> (
312 5238 : new AST::Crate (std::move (items), std::move (inner_attrs)));
313 5238 : }
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 13405 : Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
319 : {
320 13405 : const_TokenPtr t = lexer.peek_token ();
321 :
322 13405 : if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
323 : {
324 13390 : lexer.skip_token ();
325 13390 : 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 13405 : }
333 :
334 : template <typename ManagedTokenSource>
335 : bool
336 5453 : Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
337 : {
338 5453 : auto macro_name = lexer.peek_token (2)->get_id ();
339 :
340 5453 : bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
341 :
342 5453 : return t->get_str () == Values::WeakKeywords::MACRO_RULES
343 5461 : && 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 44823 : 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 44823 : AST::AttrVec outer_attrs = parse_outer_attributes ();
363 44823 : const_TokenPtr t = lexer.peek_token ();
364 :
365 44823 : 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 39559 : 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 39559 : auto vis_item = parse_vis_item (std::move (outer_attrs));
403 39559 : if (!vis_item)
404 62 : return Parse::Error::Item::make_malformed ();
405 39497 : return RType{std::move (vis_item)};
406 39559 : }
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 5254 : case IDENTIFIER:
421 : // TODO: ensure std::string and literal comparison works
422 5254 : if (t->get_str () == Values::WeakKeywords::UNION
423 5321 : && 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 5187 : else if (t->get_str () == Values::WeakKeywords::DEFAULT
432 5189 : && 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 10372 : else if (is_macro_rules_def (t))
439 : {
440 : // macro_rules! macro item
441 1247 : auto macro_rule_def = parse_macro_rules_def (std::move (outer_attrs));
442 1247 : if (!macro_rule_def)
443 13 : return Parse::Error::Item::make_malformed ();
444 1234 : return RType{std::move (macro_rule_def)};
445 1247 : }
446 7878 : else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
447 7877 : || lexer.peek_token (1)->get_id () == EXCLAM)
448 : {
449 : /* path (probably) or macro invocation, so probably a macro invocation
450 : * semi */
451 3936 : auto macro_invocation_semi
452 3936 : = parse_macro_invocation_semi (std::move (outer_attrs));
453 3936 : if (!macro_invocation_semi)
454 1 : return Parse::Error::Item::make_malformed ();
455 3935 : return RType{std::move (macro_invocation_semi)};
456 3936 : }
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 44823 : }
470 :
471 : // Parses a VisItem (item that can have non-default visibility).
472 : template <typename ManagedTokenSource>
473 : std::unique_ptr<AST::VisItem>
474 40803 : Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
475 : {
476 : // parse visibility, which may or may not exist
477 40803 : auto vis_res = parse_visibility ();
478 40803 : if (!vis_res)
479 0 : return nullptr;
480 40803 : auto vis = vis_res.value ();
481 :
482 : // select VisItem to create depending on keyword
483 40803 : const_TokenPtr t = lexer.peek_token ();
484 :
485 40803 : switch (t->get_id ())
486 : {
487 1815 : case MOD:
488 1815 : return parse_module (std::move (vis), std::move (outer_attrs));
489 1859 : case EXTERN_KW:
490 : // lookahead to resolve syntactical production
491 1859 : t = lexer.peek_token (1);
492 :
493 1859 : 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 1788 : case STRING_LITERAL: // for specifying extern ABI
502 : // could be extern block or extern function, so more lookahead
503 1788 : t = lexer.peek_token (2);
504 :
505 1788 : switch (t->get_id ())
506 : {
507 2 : case FN_KW:
508 2 : return parse_function (std::move (vis), std::move (outer_attrs));
509 1786 : case LEFT_CURLY:
510 1786 : return parse_extern_block (std::move (vis),
511 1786 : 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 7451 : case FN_KW:
533 7451 : return parse_function (std::move (vis), std::move (outer_attrs));
534 112 : case TYPE:
535 112 : return parse_type_alias (std::move (vis), std::move (outer_attrs));
536 3885 : case STRUCT_KW:
537 3885 : return parse_struct (std::move (vis), std::move (outer_attrs));
538 670 : case ENUM_KW:
539 670 : 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 1215 : case CONST:
557 : // lookahead to resolve syntactical production
558 1215 : t = lexer.peek_token (1);
559 :
560 1215 : switch (t->get_id ())
561 : {
562 1091 : case IDENTIFIER:
563 : case UNDERSCORE:
564 1091 : 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 136 : case STATIC_KW:
585 136 : return parse_static_item (std::move (vis), std::move (outer_attrs));
586 4499 : case AUTO:
587 : case TRAIT:
588 4499 : return parse_trait (std::move (vis), std::move (outer_attrs));
589 12798 : case IMPL:
590 12798 : return parse_impl (std::move (vis), std::move (outer_attrs));
591 4117 : case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls),
592 : // lookahead to resolve syntactical production
593 4117 : t = lexer.peek_token (1);
594 :
595 4117 : switch (t->get_id ())
596 : {
597 85 : case AUTO:
598 : case TRAIT:
599 85 : return parse_trait (std::move (vis), std::move (outer_attrs));
600 3733 : case EXTERN_KW:
601 : case FN_KW:
602 3733 : return parse_function (std::move (vis), std::move (outer_attrs));
603 297 : case IMPL:
604 297 : 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 40803 : }
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 1766 : Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
664 : {
665 : // ensure that first token is identifier saying "macro_rules"
666 1766 : const_TokenPtr t = lexer.peek_token ();
667 1766 : if (t->get_id () != IDENTIFIER
668 1766 : || 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 1766 : lexer.skip_token ();
679 1766 : location_t macro_locus = t->get_locus ();
680 :
681 1766 : if (!skip_token (EXCLAM))
682 : {
683 : // skip after somewhere?
684 0 : return nullptr;
685 : }
686 :
687 : // parse macro name
688 1766 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
689 1766 : if (ident_tok == nullptr)
690 : {
691 1 : return nullptr;
692 : }
693 3530 : Identifier rule_name{ident_tok};
694 :
695 : // DEBUG
696 1765 : rust_debug ("in macro rules def, about to parse parens.");
697 :
698 : // save delim type to ensure it is reused later
699 1765 : AST::DelimType delim_type = AST::PARENS;
700 :
701 : // Map tokens to DelimType
702 1765 : t = lexer.peek_token ();
703 1765 : 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 1764 : case LEFT_CURLY:
712 1764 : delim_type = AST::CURLY;
713 1764 : 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 1765 : lexer.skip_token ();
723 :
724 : // parse actual macro rules
725 1765 : std::vector<AST::MacroRule> macro_rules;
726 :
727 : // must be at least one macro rule, so parse it
728 1765 : AST::MacroRule initial_rule = parse_macro_rule ();
729 1765 : 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 1753 : macro_rules.push_back (std::move (initial_rule));
740 :
741 : // DEBUG
742 1753 : rust_debug ("successfully pushed back initial macro rule");
743 :
744 1753 : t = lexer.peek_token ();
745 : // parse macro rules
746 1925 : while (t->get_id () == SEMICOLON)
747 : {
748 : // skip semicolon
749 1321 : lexer.skip_token ();
750 :
751 : // don't parse if end of macro rules
752 2642 : if (Parse::Utils::token_id_matches_delims (lexer.peek_token ()->get_id (),
753 : delim_type))
754 : {
755 : // DEBUG
756 1149 : rust_debug (
757 : "broke out of parsing macro rules loop due to finding delim");
758 :
759 1149 : 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 1753 : t = lexer.peek_token ();
783 1753 : if (Parse::Utils::token_id_matches_delims (t->get_id (), delim_type))
784 : {
785 : // tokens match opening delimiter, so skip.
786 1753 : lexer.skip_token ();
787 :
788 1753 : if (delim_type != AST::CURLY)
789 : {
790 : // skip semicolon at end of non-curly macro definitions
791 1 : 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 3506 : AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
803 : std::move (macro_rules),
804 1753 : 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 5296 : }
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 77741 : Parser<ManagedTokenSource>::parse_visibility ()
991 : {
992 : // check for no visibility
993 155482 : if (lexer.peek_token ()->get_id () != PUB)
994 : {
995 60699 : return AST::Visibility::create_private ();
996 : }
997 :
998 17042 : auto vis_loc = lexer.peek_token ()->get_locus ();
999 17042 : lexer.skip_token ();
1000 :
1001 : // create simple pub visibility if
1002 : // - found no parentheses
1003 : // - found unit type `()`
1004 34084 : if (lexer.peek_token ()->get_id () != LEFT_PAREN
1005 17458 : || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
1006 : {
1007 16627 : 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 1816 : Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
1070 : AST::AttrVec outer_attrs)
1071 : {
1072 1816 : location_t locus = lexer.peek_token ()->get_locus ();
1073 :
1074 1816 : Unsafety safety = Unsafety::Normal;
1075 3632 : if (lexer.peek_token ()->get_id () == UNSAFE)
1076 : {
1077 1 : safety = Unsafety::Unsafe;
1078 1 : skip_token (UNSAFE);
1079 : }
1080 :
1081 1816 : skip_token (MOD);
1082 :
1083 1816 : const_TokenPtr module_name = expect_token (IDENTIFIER);
1084 1816 : if (module_name == nullptr)
1085 : {
1086 0 : return nullptr;
1087 : }
1088 3632 : Identifier name{module_name};
1089 :
1090 1816 : const_TokenPtr t = lexer.peek_token ();
1091 :
1092 1816 : 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 1481 : case LEFT_CURLY:
1103 : {
1104 1481 : lexer.skip_token ();
1105 :
1106 : // parse inner attributes
1107 1481 : AST::AttrVec inner_attrs = parse_inner_attributes ();
1108 :
1109 1481 : std::string default_path = name.as_string ();
1110 :
1111 1481 : if (inline_module_stack.empty ())
1112 : {
1113 1060 : std::string filename = lexer.get_filename ();
1114 1060 : auto slash_idx = filename.rfind (file_separator);
1115 1060 : if (slash_idx == std::string::npos)
1116 : slash_idx = 0;
1117 : else
1118 1060 : slash_idx++;
1119 1060 : filename = filename.substr (slash_idx);
1120 :
1121 1060 : std::string subdir;
1122 1060 : if (get_file_subdir (filename, subdir))
1123 1047 : default_path = subdir + file_separator + name.as_string ();
1124 1060 : }
1125 :
1126 1481 : std::string module_path_name
1127 : = extract_module_path (inner_attrs, outer_attrs, default_path);
1128 1481 : InlineModuleStackScope scope (*this, std::move (module_path_name));
1129 :
1130 : // parse items
1131 1481 : std::vector<std::unique_ptr<AST::Item>> items;
1132 1481 : const_TokenPtr tok = lexer.peek_token ();
1133 6992 : while (tok->get_id () != RIGHT_CURLY)
1134 : {
1135 5511 : auto item = parse_item (false);
1136 5511 : 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 5510 : items.push_back (std::move (item.value ()));
1146 :
1147 5510 : tok = lexer.peek_token ();
1148 : }
1149 :
1150 1480 : if (!skip_token (RIGHT_CURLY))
1151 : {
1152 : // skip somewhere?
1153 0 : return nullptr;
1154 : }
1155 :
1156 : return std::unique_ptr<AST::Module> (
1157 1480 : new AST::Module (std::move (name), locus, std::move (items),
1158 : std::move (vis), safety, std::move (inner_attrs),
1159 1480 : std::move (outer_attrs))); // module name?
1160 1481 : }
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 1816 : }
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 18161 : Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
1557 : AST::AttrVec outer_attrs,
1558 : bool is_external)
1559 : {
1560 18161 : location_t locus = lexer.peek_token ()->get_locus ();
1561 : // Get qualifiers for function if they exist
1562 18161 : auto qualifiers = parse_function_qualifiers ();
1563 18161 : if (!qualifiers)
1564 1 : return nullptr;
1565 :
1566 18160 : skip_token (FN_KW);
1567 :
1568 : // Save function name token
1569 18160 : const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
1570 18160 : if (function_name_tok == nullptr)
1571 : {
1572 0 : skip_after_next_block ();
1573 0 : return nullptr;
1574 : }
1575 36320 : Identifier function_name{function_name_tok};
1576 :
1577 : // parse generic params - if exist
1578 18160 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
1579 : = parse_generic_params_in_angles ();
1580 :
1581 18160 : 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 18160 : auto initial_param = parse_self_param ();
1593 :
1594 18160 : if (!initial_param.has_value ()
1595 18160 : && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
1596 0 : return nullptr;
1597 :
1598 21034 : if (initial_param.has_value () && lexer.peek_token ()->get_id () == COMMA)
1599 1713 : skip_token ();
1600 :
1601 : // parse function parameters (only if next token isn't right paren)
1602 18160 : std::vector<std::unique_ptr<AST::Param>> function_params;
1603 :
1604 36320 : if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
1605 : function_params
1606 9045 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
1607 :
1608 18160 : if (initial_param.has_value ())
1609 2874 : function_params.insert (function_params.begin (),
1610 2874 : std::move (*initial_param));
1611 :
1612 18160 : 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 18159 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
1625 :
1626 : // parse where clause - if exists
1627 18159 : AST::WhereClause where_clause = parse_where_clause ();
1628 :
1629 18159 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
1630 36318 : if (lexer.peek_token ()->get_id () == SEMICOLON)
1631 5761 : lexer.skip_token ();
1632 : else
1633 : {
1634 12398 : auto block_expr = parse_block_expr ();
1635 12398 : if (!block_expr)
1636 30 : return nullptr;
1637 12368 : body = std::move (block_expr.value ());
1638 12398 : }
1639 :
1640 48626 : return std::unique_ptr<AST::Function> (new AST::Function (
1641 18129 : 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 18129 : std::move (vis), std::move (outer_attrs), locus, is_external));
1645 54480 : }
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 36533 : Parser<ManagedTokenSource>::parse_function_qualifiers ()
1651 : {
1652 36533 : location_t locus = lexer.peek_token ()->get_locus ();
1653 :
1654 36533 : auto parsed = parse_function_qualifiers_raw (locus);
1655 36533 : if (!parsed)
1656 3 : return tl::unexpected<Parse::Error::Node> (parsed.error ());
1657 :
1658 73060 : return function_qualifiers_from_keywords (locus, std::move (parsed->first),
1659 73060 : std::move (parsed->second));
1660 36533 : }
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 36530 : Parser<ManagedTokenSource>::function_qualifiers_from_keywords (
1670 : location_t locus, const std::vector<TokenId> keywords, std::string abi)
1671 : {
1672 36530 : Default default_status = Default::No;
1673 36530 : Async async_status = Async::No;
1674 36530 : Const const_status = Const::No;
1675 36530 : Unsafety unsafe_status = Unsafety::Normal;
1676 36530 : bool has_extern = false;
1677 :
1678 44546 : for (auto qualifier : keywords)
1679 : {
1680 8016 : 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 2399 : case CONST:
1687 2399 : const_status = Const::Yes;
1688 2399 : continue;
1689 11 : case ASYNC:
1690 11 : async_status = Async::Yes;
1691 11 : continue;
1692 4776 : case UNSAFE:
1693 4776 : unsafe_status = Unsafety::Unsafe;
1694 4776 : continue;
1695 756 : case EXTERN_KW:
1696 756 : has_extern = true;
1697 756 : continue;
1698 0 : default:
1699 : // non-qualifier token in input
1700 0 : rust_unreachable ();
1701 : }
1702 : }
1703 :
1704 73060 : return AST::FunctionQualifiers (locus, default_status, async_status,
1705 : const_status, unsafe_status, has_extern,
1706 36530 : 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 36533 : Parser<ManagedTokenSource>::parse_function_qualifiers_raw (location_t locus)
1714 : {
1715 36533 : std::vector<TokenId> found_order;
1716 36533 : std::string abi;
1717 :
1718 : // this will terminate on duplicates or the first non-qualifier token
1719 8026 : while (true)
1720 : {
1721 44558 : auto token = lexer.peek_token ();
1722 44558 : const TokenId token_id = token->get_id ();
1723 44558 : location_t locus = lexer.peek_token ()->get_locus ();
1724 :
1725 44558 : 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 7269 : found_order.push_back (token_id);
1739 7269 : lexer.skip_token ();
1740 7269 : break;
1741 757 : case EXTERN_KW:
1742 : {
1743 757 : found_order.push_back (token_id);
1744 757 : lexer.skip_token ();
1745 :
1746 : // detect optional abi name
1747 757 : const_TokenPtr next_tok = lexer.peek_token ();
1748 757 : if (next_tok->get_id () == STRING_LITERAL)
1749 : {
1750 757 : abi = next_tok->get_str ();
1751 757 : lexer.skip_token ();
1752 : }
1753 757 : }
1754 757 : break;
1755 36532 : default:
1756 : // non-qualifier keyword
1757 36532 : goto done;
1758 : }
1759 :
1760 16052 : 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 36532 : done:
1772 :
1773 36532 : if (!ensure_function_qualifier_order (locus, found_order))
1774 2 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
1775 :
1776 73060 : return make_pair (found_order, abi);
1777 36533 : }
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 36532 : 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 8023 : auto token_priority = [] (const TokenId id) {
1792 8023 : switch (id)
1793 : {
1794 : case IDENTIFIER: // "default"; the only "weak" keyword considered here
1795 : return 1;
1796 2400 : case CONST:
1797 2400 : return 2;
1798 12 : case ASYNC:
1799 12 : return 3;
1800 4778 : case UNSAFE:
1801 4778 : return 4;
1802 757 : case EXTERN_KW:
1803 757 : return 5;
1804 0 : default:
1805 0 : rust_unreachable ();
1806 : };
1807 : };
1808 :
1809 36532 : size_t last_priority = 0;
1810 44553 : for (auto token_id : found_order)
1811 : {
1812 8023 : const size_t priority = token_priority (token_id);
1813 8023 : if (priority <= last_priority)
1814 : {
1815 2 : emit_function_qualifier_order_error_msg (locus, found_order);
1816 2 : return false;
1817 : }
1818 :
1819 8021 : 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 62554 : Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
1880 : {
1881 125108 : if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
1882 : {
1883 : // seems to be no generic params, so exit with empty vector
1884 52925 : return std::vector<std::unique_ptr<AST::GenericParam>> ();
1885 : }
1886 9629 : lexer.skip_token ();
1887 :
1888 : // DEBUG:
1889 9629 : rust_debug ("skipped left angle in generic param");
1890 :
1891 9629 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
1892 : = parse_generic_params (Parse::Utils::is_right_angle_tok);
1893 :
1894 : // DEBUG:
1895 9629 : rust_debug ("finished parsing actual generic params (i.e. inside angles)");
1896 :
1897 9629 : 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 9628 : return generic_params;
1907 9629 : }
1908 :
1909 : template <typename ManagedTokenSource>
1910 : template <typename EndTokenPred>
1911 : std::unique_ptr<AST::GenericParam>
1912 15705 : Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
1913 : {
1914 15705 : auto outer_attrs = parse_outer_attributes ();
1915 15705 : std::unique_ptr<AST::GenericParam> param;
1916 15705 : auto token = lexer.peek_token ();
1917 :
1918 15705 : switch (token->get_id ())
1919 : {
1920 1716 : case LIFETIME:
1921 : {
1922 1716 : auto lifetime = parse_lifetime (false);
1923 1716 : 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 1716 : std::vector<AST::Lifetime> lifetime_bounds;
1933 3432 : 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 3432 : param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam (
1944 1716 : std::move (lifetime.value ()), std::move (lifetime_bounds),
1945 1716 : std::move (outer_attrs), token->get_locus ()));
1946 : break;
1947 3432 : }
1948 13783 : case IDENTIFIER:
1949 : {
1950 13783 : auto type_ident = token->get_str ();
1951 13783 : lexer.skip_token ();
1952 :
1953 13783 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
1954 27566 : if (lexer.peek_token ()->get_id () == COLON)
1955 : {
1956 3140 : lexer.skip_token ();
1957 :
1958 : // parse optional type param bounds
1959 3140 : type_param_bounds = parse_type_param_bounds ();
1960 : }
1961 :
1962 13783 : std::unique_ptr<AST::Type> type = nullptr;
1963 27566 : if (lexer.peek_token ()->get_id () == EQUAL)
1964 : {
1965 453 : lexer.skip_token ();
1966 :
1967 : // parse required type
1968 453 : type = parse_type ();
1969 453 : 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 13783 : param = std::unique_ptr<AST::TypeParam> (
1981 41349 : new AST::TypeParam (std::move (type_ident), token->get_locus (),
1982 : std::move (type_param_bounds), std::move (type),
1983 13783 : std::move (outer_attrs)));
1984 : break;
1985 13783 : }
1986 205 : case CONST:
1987 : {
1988 205 : lexer.skip_token ();
1989 :
1990 205 : auto name_token = expect_token (IDENTIFIER);
1991 :
1992 410 : if (!name_token || !expect_token (COLON))
1993 1 : return nullptr;
1994 :
1995 204 : auto type = parse_type ();
1996 204 : if (!type)
1997 1 : return nullptr;
1998 :
1999 : // optional default value
2000 203 : tl::optional<AST::GenericArg> default_expr = tl::nullopt;
2001 406 : 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 202 : param = std::unique_ptr<AST::ConstGenericParam> (
2037 830 : new AST::ConstGenericParam (name_token->get_str (), std::move (type),
2038 : default_expr, std::move (outer_attrs),
2039 202 : token->get_locus ()));
2040 :
2041 : break;
2042 409 : }
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 15701 : return param;
2054 15705 : }
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 9629 : Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
2062 : {
2063 9629 : 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 9629 : AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
2071 :
2072 : // Did we parse a generic type param yet
2073 9629 : auto type_seen = false;
2074 : // Did we parse a const param with a default value yet
2075 9629 : auto const_with_default_seen = false;
2076 : // Did the user write a lifetime parameter after a type one
2077 9629 : auto order_error = false;
2078 : // Did the user write a const param with a default value after a type one
2079 9629 : auto const_with_default_order_error = false;
2080 :
2081 : // parse lifetime params
2082 66365 : while (!is_end_token (lexer.peek_token ()->get_id ()))
2083 : {
2084 15705 : auto param = parse_generic_param (is_end_token);
2085 15705 : if (param)
2086 : {
2087 15701 : if (param->get_kind () == AST::GenericParam::Kind::Type)
2088 : {
2089 13783 : type_seen = true;
2090 13783 : if (const_with_default_seen)
2091 15701 : const_with_default_order_error = true;
2092 : }
2093 1918 : else if (param->get_kind () == AST::GenericParam::Kind::Lifetime
2094 1918 : && 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 1916 : else if (param->get_kind () == AST::GenericParam::Kind::Const)
2101 : {
2102 202 : type_seen = true;
2103 : AST::ConstGenericParam *const_param
2104 202 : = static_cast<AST::ConstGenericParam *> (param.get ());
2105 202 : if (const_param->has_default_value ())
2106 : const_with_default_seen = true;
2107 180 : else if (const_with_default_seen)
2108 15701 : const_with_default_order_error = true;
2109 : }
2110 :
2111 15701 : generic_params.emplace_back (std::move (param));
2112 15701 : maybe_skip_token (COMMA);
2113 : }
2114 : else
2115 : break;
2116 : }
2117 :
2118 : // FIXME: Add reordering hint
2119 9629 : 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 9629 : 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 9629 : generic_params.shrink_to_fit ();
2135 9629 : return generic_params;
2136 9629 : }
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 23393 : Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
2488 : {
2489 23393 : std::vector<std::unique_ptr<AST::Param>> params;
2490 :
2491 46786 : if (is_end_token (lexer.peek_token ()->get_id ()))
2492 2098 : return params;
2493 :
2494 21295 : auto initial_param = parse_function_param ();
2495 :
2496 : // Return empty parameter list if no parameter there
2497 21295 : if (initial_param == nullptr)
2498 : {
2499 : // TODO: is this an error?
2500 1 : return params;
2501 : }
2502 :
2503 21294 : 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 21294 : const_TokenPtr t = lexer.peek_token ();
2509 28781 : while (t->get_id () == COMMA)
2510 : {
2511 : // skip comma if applies
2512 7810 : lexer.skip_token ();
2513 :
2514 : // TODO: strictly speaking, shouldn't there be no trailing comma?
2515 15620 : if (is_end_token (lexer.peek_token ()->get_id ()))
2516 : break;
2517 :
2518 : // now, as right paren would break, function param is required
2519 7487 : auto param = parse_function_param ();
2520 7487 : 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 7487 : params.push_back (std::move (param));
2531 :
2532 7487 : t = lexer.peek_token ();
2533 : }
2534 :
2535 21294 : params.shrink_to_fit ();
2536 21294 : return params;
2537 23393 : }
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 28782 : Parser<ManagedTokenSource>::parse_function_param ()
2544 : {
2545 : // parse outer attributes if they exist
2546 28782 : AST::AttrVec outer_attrs = parse_outer_attributes ();
2547 :
2548 : // TODO: should saved location be at start of outer attributes or pattern?
2549 28782 : location_t locus = lexer.peek_token ()->get_locus ();
2550 :
2551 57564 : 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 27895 : std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
2559 :
2560 : // create error function param if it doesn't exist
2561 27895 : if (param_pattern == nullptr)
2562 : {
2563 : // skip after something
2564 1 : return nullptr;
2565 : }
2566 :
2567 27894 : if (!skip_token (COLON))
2568 : {
2569 : // skip after something
2570 0 : return nullptr;
2571 : }
2572 :
2573 55788 : 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 27883 : std::unique_ptr<AST::Type> param_type = parse_type ();
2583 27883 : if (param_type == nullptr)
2584 : {
2585 0 : return nullptr;
2586 : }
2587 27883 : return std::make_unique<AST::FunctionParam> (
2588 55766 : AST::FunctionParam (std::move (param_pattern), std::move (param_type),
2589 27883 : std::move (outer_attrs), locus));
2590 27883 : }
2591 28782 : }
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 36438 : Parser<ManagedTokenSource>::parse_function_return_type ()
2598 : {
2599 72876 : if (lexer.peek_token ()->get_id () != RETURN_TYPE)
2600 9624 : return nullptr;
2601 :
2602 : // skip return type, as it now obviously exists
2603 26814 : lexer.skip_token ();
2604 :
2605 26814 : std::unique_ptr<AST::Type> type = parse_type ();
2606 :
2607 26814 : return type;
2608 26814 : }
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 62531 : Parser<ManagedTokenSource>::parse_where_clause ()
2617 : {
2618 62531 : const_TokenPtr where_tok = lexer.peek_token ();
2619 62531 : if (where_tok->get_id () != WHERE)
2620 : {
2621 : // where clause doesn't exist, so create empty one
2622 61221 : return AST::WhereClause::create_empty ();
2623 : }
2624 :
2625 1310 : 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 1310 : std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items;
2630 :
2631 1310 : std::vector<AST::LifetimeParam> for_lifetimes;
2632 2620 : 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 1310 : const_TokenPtr t = lexer.peek_token ();
2638 2978 : while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON
2639 2783 : && t->get_id () != EQUAL)
2640 : {
2641 1668 : std::unique_ptr<AST::WhereClauseItem> where_clause_item
2642 : = parse_where_clause_item (for_lifetimes);
2643 :
2644 1668 : 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 1668 : where_clause_items.push_back (std::move (where_clause_item));
2653 :
2654 : // also skip comma if it exists
2655 3336 : if (lexer.peek_token ()->get_id () != COMMA)
2656 : break;
2657 :
2658 1473 : lexer.skip_token ();
2659 1473 : t = lexer.peek_token ();
2660 : }
2661 :
2662 1310 : where_clause_items.shrink_to_fit ();
2663 1310 : return AST::WhereClause (std::move (where_clause_items));
2664 1310 : }
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 1668 : 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 1668 : const_TokenPtr t = lexer.peek_token ();
2676 :
2677 1668 : if (t->get_id () == LIFETIME)
2678 3 : return parse_lifetime_where_clause_item ();
2679 : else
2680 1665 : return parse_type_bound_where_clause_item (outer_for_lifetimes);
2681 1668 : }
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 1665 : Parser<ManagedTokenSource>::parse_type_bound_where_clause_item (
2716 : const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
2717 : {
2718 1665 : std::vector<AST::LifetimeParam> for_lifetimes = outer_for_lifetimes;
2719 :
2720 1665 : std::unique_ptr<AST::Type> type = parse_type ();
2721 1665 : if (type == nullptr)
2722 : {
2723 0 : return nullptr;
2724 : }
2725 :
2726 1665 : if (!skip_token (COLON))
2727 : {
2728 : // TODO: skip after somewhere
2729 0 : return nullptr;
2730 : }
2731 :
2732 3330 : 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 1665 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds
2741 : = parse_type_param_bounds ();
2742 :
2743 1665 : location_t locus = lexer.peek_token ()->get_locus ();
2744 :
2745 : return std::unique_ptr<AST::TypeBoundWhereClauseItem> (
2746 1665 : new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes),
2747 : std::move (type),
2748 1665 : std::move (type_param_bounds), locus));
2749 1665 : }
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 4900 : Parser<ManagedTokenSource>::parse_type_param_bounds ()
2793 : {
2794 4900 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
2795 :
2796 4900 : std::unique_ptr<AST::TypeParamBound> initial_bound
2797 : = parse_type_param_bound ();
2798 :
2799 : // quick exit if null
2800 4900 : 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 4900 : type_param_bounds.push_back (std::move (initial_bound));
2807 :
2808 10522 : 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 4900 : type_param_bounds.shrink_to_fit ();
2824 : return type_param_bounds;
2825 4900 : }
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 742 : Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token)
2833 : {
2834 742 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
2835 :
2836 742 : std::unique_ptr<AST::TypeParamBound> initial_bound
2837 : = parse_type_param_bound ();
2838 :
2839 : // quick exit if null
2840 742 : 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 742 : type_param_bounds.push_back (std::move (initial_bound));
2847 :
2848 1694 : 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 742 : type_param_bounds.shrink_to_fit ();
2871 742 : return type_param_bounds;
2872 742 : }
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 6182 : Parser<ManagedTokenSource>::parse_type_param_bound ()
2879 : {
2880 : // shitty cheat way of determining lifetime or trait bound - test for
2881 : // lifetime
2882 6182 : const_TokenPtr t = lexer.peek_token ();
2883 6182 : switch (t->get_id ())
2884 : {
2885 293 : case LIFETIME:
2886 293 : return std::unique_ptr<AST::Lifetime> (
2887 586 : new AST::Lifetime (parse_lifetime (false).value ()));
2888 5889 : 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 5889 : return parse_trait_bound ();
2899 0 : default:
2900 : // don't error - assume this is fine TODO
2901 0 : return nullptr;
2902 : }
2903 6182 : }
2904 :
2905 : // Parses a trait bound type param bound.
2906 : template <typename ManagedTokenSource>
2907 : std::unique_ptr<AST::TraitBound>
2908 6439 : Parser<ManagedTokenSource>::parse_trait_bound ()
2909 : {
2910 6439 : bool has_parens = false;
2911 6439 : bool has_question_mark = false;
2912 :
2913 6439 : location_t locus = lexer.peek_token ()->get_locus ();
2914 :
2915 : /* parse optional `for lifetimes`. */
2916 6439 : std::vector<AST::LifetimeParam> for_lifetimes;
2917 12878 : if (lexer.peek_token ()->get_id () == FOR)
2918 7 : for_lifetimes = parse_for_lifetimes ();
2919 :
2920 : // handle trait bound being in parentheses
2921 12878 : 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 12878 : if (lexer.peek_token ()->get_id () == QUESTION_MARK)
2929 : {
2930 948 : has_question_mark = true;
2931 948 : lexer.skip_token ();
2932 : }
2933 :
2934 : // handle TypePath
2935 6439 : AST::TypePath type_path = parse_type_path ();
2936 6439 : if (type_path.is_error ())
2937 2 : return nullptr;
2938 :
2939 : // handle closing parentheses
2940 6437 : 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 6437 : new AST::TraitBound (std::move (type_path), locus, has_parens,
2950 6437 : has_question_mark, std::move (for_lifetimes)));
2951 6439 : }
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 27904 : Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided)
3024 : {
3025 27904 : const_TokenPtr lifetime_tok = lexer.peek_token ();
3026 27904 : if (lifetime_tok->get_id () != LIFETIME)
3027 : {
3028 21615 : if (allow_elided)
3029 : {
3030 0 : return AST::Lifetime::elided ();
3031 : }
3032 : else
3033 : {
3034 21615 : return tl::make_unexpected<Parse::Error::Lifetime> ({});
3035 : }
3036 : }
3037 6289 : lexer.skip_token ();
3038 :
3039 12578 : return lifetime_from_token (lifetime_tok);
3040 27904 : }
3041 :
3042 : template <typename ManagedTokenSource>
3043 : AST::Lifetime
3044 6350 : Parser<ManagedTokenSource>::lifetime_from_token (const_TokenPtr tok)
3045 : {
3046 6350 : location_t locus = tok->get_locus ();
3047 6350 : std::string lifetime_ident = tok->get_str ();
3048 :
3049 6350 : if (lifetime_ident == "static")
3050 : {
3051 145 : return AST::Lifetime (AST::Lifetime::STATIC, "", locus);
3052 : }
3053 6205 : else if (lifetime_ident == "_")
3054 : {
3055 : // Explicitly and implicitly elided lifetimes follow the same rules.
3056 1059 : return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus);
3057 : }
3058 : else
3059 : {
3060 10292 : return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident),
3061 5146 : locus);
3062 : }
3063 6350 : }
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 4367 : Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis,
3096 : AST::AttrVec outer_attrs)
3097 : {
3098 4367 : location_t locus = lexer.peek_token ()->get_locus ();
3099 4367 : skip_token (TYPE);
3100 :
3101 : // TODO: use this token for identifier when finished that
3102 4367 : const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
3103 4367 : 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 8734 : Identifier alias_name{alias_name_tok};
3113 :
3114 : // parse generic params, which may not exist
3115 4367 : 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 4367 : AST::WhereClause where_clause = parse_where_clause ();
3120 :
3121 4367 : if (!skip_token (EQUAL))
3122 : {
3123 0 : skip_after_semicolon ();
3124 0 : return nullptr;
3125 : }
3126 :
3127 4367 : std::unique_ptr<AST::Type> type_to_alias = parse_type ();
3128 :
3129 4367 : 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 4367 : new AST::TypeAlias (std::move (alias_name), std::move (generic_params),
3137 : std::move (where_clause), std::move (type_to_alias),
3138 4367 : std::move (vis), std::move (outer_attrs), locus));
3139 8734 : }
3140 :
3141 : // Parse a struct item AST node.
3142 : template <typename ManagedTokenSource>
3143 : std::unique_ptr<AST::Struct>
3144 3885 : 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 3885 : location_t locus = lexer.peek_token ()->get_locus ();
3159 3885 : skip_token (STRUCT_KW);
3160 :
3161 : // parse struct name
3162 3885 : const_TokenPtr name_tok = expect_token (IDENTIFIER);
3163 3885 : if (name_tok == nullptr)
3164 : {
3165 : // skip after somewhere?
3166 1 : return nullptr;
3167 : }
3168 7768 : Identifier struct_name{name_tok};
3169 :
3170 : // parse generic params, which may or may not exist
3171 3884 : 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 7768 : if (lexer.peek_token ()->get_id () == LEFT_PAREN)
3176 : {
3177 : // tuple struct
3178 :
3179 : // skip left parenthesis
3180 1194 : lexer.skip_token ();
3181 :
3182 : // parse tuple fields
3183 1194 : std::vector<AST::TupleField> tuple_fields;
3184 : // Might be empty tuple for unit tuple struct.
3185 2388 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3186 23 : tuple_fields = std::vector<AST::TupleField> ();
3187 : else
3188 1171 : tuple_fields = parse_tuple_fields ();
3189 :
3190 : // tuple parameters must have closing parenthesis
3191 1194 : 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 1193 : AST::WhereClause where_clause = parse_where_clause ();
3199 :
3200 1193 : 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 1193 : return std::unique_ptr<AST::TupleStruct> (
3207 1193 : 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 1193 : std::move (outer_attrs), locus));
3211 1194 : }
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 2690 : AST::WhereClause where_clause = parse_where_clause ();
3218 :
3219 : // branch on next token - determines whether struct is a unit struct
3220 2690 : const_TokenPtr t = lexer.peek_token ();
3221 2690 : switch (t->get_id ())
3222 : {
3223 1450 : case LEFT_CURLY:
3224 : {
3225 : // struct with body
3226 :
3227 : // skip curly bracket
3228 1450 : lexer.skip_token ();
3229 :
3230 : // parse struct fields, if any
3231 1450 : std::vector<AST::StructField> struct_fields
3232 : = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
3233 :
3234 1450 : if (!skip_token (RIGHT_CURLY))
3235 : {
3236 : // skip somewhere?
3237 0 : return nullptr;
3238 : }
3239 :
3240 1450 : 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 1450 : std::move (vis), std::move (outer_attrs), locus));
3244 1450 : }
3245 1239 : case SEMICOLON:
3246 : // unit struct declaration
3247 :
3248 1239 : lexer.skip_token ();
3249 :
3250 1239 : return std::unique_ptr<AST::StructStruct> (
3251 2478 : new AST::StructStruct (std::move (struct_name),
3252 : std::move (generic_params),
3253 : std::move (where_clause), std::move (vis),
3254 1239 : 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 3884 : }
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 1666 : Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
3305 : {
3306 1666 : std::vector<AST::StructField> fields;
3307 :
3308 1666 : AST::StructField initial_field = parse_struct_field ();
3309 :
3310 : // Return empty field list if no field there
3311 1666 : if (initial_field.is_error ())
3312 59 : return fields;
3313 :
3314 1607 : fields.push_back (std::move (initial_field));
3315 :
3316 6394 : while (lexer.peek_token ()->get_id () == COMMA)
3317 : {
3318 2988 : lexer.skip_token ();
3319 :
3320 5976 : if (is_end_tok (lexer.peek_token ()->get_id ()))
3321 : break;
3322 :
3323 1590 : AST::StructField field = parse_struct_field ();
3324 1590 : 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 1590 : fields.push_back (std::move (field));
3336 : }
3337 :
3338 1607 : fields.shrink_to_fit ();
3339 1607 : return fields;
3340 : // TODO: template if possible (parse_non_ptr_seq)
3341 1666 : }
3342 :
3343 : // Parses a single struct field (in a struct definition). Does not parse
3344 : // commas.
3345 : template <typename ManagedTokenSource>
3346 : AST::StructField
3347 3256 : Parser<ManagedTokenSource>::parse_struct_field ()
3348 : {
3349 : // parse outer attributes, if they exist
3350 3256 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3351 :
3352 : // parse visibility, if it exists
3353 3256 : auto vis = parse_visibility ();
3354 3256 : if (!vis)
3355 0 : return AST::StructField::create_error ();
3356 :
3357 3256 : location_t locus = lexer.peek_token ()->get_locus ();
3358 :
3359 : // parse field name
3360 3256 : const_TokenPtr field_name_tok = lexer.peek_token ();
3361 3256 : 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 59 : return AST::StructField::create_error ();
3366 : }
3367 6394 : Identifier field_name{field_name_tok};
3368 3197 : lexer.skip_token ();
3369 :
3370 3197 : 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 3197 : std::unique_ptr<AST::Type> field_type = parse_type ();
3378 3197 : 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 6394 : return AST::StructField (std::move (field_name), std::move (field_type),
3389 3197 : std::move (vis.value ()), locus,
3390 3197 : std::move (outer_attrs));
3391 12906 : }
3392 :
3393 : // Parses tuple fields in tuple/tuple struct declarations.
3394 : template <typename ManagedTokenSource>
3395 : std::vector<AST::TupleField>
3396 1708 : Parser<ManagedTokenSource>::parse_tuple_fields ()
3397 : {
3398 1708 : std::vector<AST::TupleField> fields;
3399 :
3400 1708 : AST::TupleField initial_field = parse_tuple_field ();
3401 :
3402 : // Return empty field list if no field there
3403 1708 : if (initial_field.is_error ())
3404 : {
3405 1 : return fields;
3406 : }
3407 :
3408 1707 : 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 1707 : const_TokenPtr t = lexer.peek_token ();
3415 2943 : while (t->get_id () == COMMA)
3416 : {
3417 : // skip comma if applies - e.g. trailing comma
3418 1239 : lexer.skip_token ();
3419 :
3420 : // break out due to right paren if it exists
3421 2478 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3422 : {
3423 : break;
3424 : }
3425 :
3426 1236 : AST::TupleField field = parse_tuple_field ();
3427 1236 : 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 1236 : fields.push_back (std::move (field));
3437 :
3438 1236 : t = lexer.peek_token ();
3439 : }
3440 :
3441 1707 : fields.shrink_to_fit ();
3442 1707 : return fields;
3443 :
3444 : // TODO: this shares basically all code with function params and struct
3445 : // fields
3446 : // - templates?
3447 1708 : }
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 2944 : Parser<ManagedTokenSource>::parse_tuple_field ()
3454 : {
3455 : // parse outer attributes if they exist
3456 2944 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3457 :
3458 : // parse visibility if it exists
3459 2944 : auto visibility = parse_visibility ();
3460 2944 : if (!visibility)
3461 0 : return AST::TupleField::create_error ();
3462 :
3463 2944 : location_t locus = lexer.peek_token ()->get_locus ();
3464 :
3465 : // parse type, which is required
3466 2944 : std::unique_ptr<AST::Type> field_type = parse_type ();
3467 2944 : 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 2943 : return AST::TupleField (std::move (field_type),
3479 2943 : std::move (visibility.value ()), locus,
3480 2943 : std::move (outer_attrs));
3481 5888 : }
3482 :
3483 : // Parses a Rust "enum" tagged union item definition.
3484 : template <typename ManagedTokenSource>
3485 : std::unique_ptr<AST::Enum>
3486 670 : Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
3487 : AST::AttrVec outer_attrs)
3488 : {
3489 670 : location_t locus = lexer.peek_token ()->get_locus ();
3490 670 : skip_token (ENUM_KW);
3491 :
3492 : // parse enum name
3493 670 : const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
3494 670 : if (enum_name_tok == nullptr)
3495 1 : return nullptr;
3496 :
3497 1338 : Identifier enum_name = {enum_name_tok};
3498 :
3499 : // parse generic params (of enum container, not enum variants) if they exist
3500 669 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3501 : = parse_generic_params_in_angles ();
3502 :
3503 : // parse where clause if it exists
3504 669 : AST::WhereClause where_clause = parse_where_clause ();
3505 :
3506 669 : 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 669 : std::vector<std::unique_ptr<AST::EnumItem>> enum_items
3514 : = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
3515 :
3516 669 : 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 668 : new AST::Enum (std::move (enum_name), std::move (vis),
3524 : std::move (generic_params), std::move (where_clause),
3525 668 : std::move (enum_items), std::move (outer_attrs), locus));
3526 1338 : }
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 669 : Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
3568 : {
3569 669 : std::vector<std::unique_ptr<AST::EnumItem>> items;
3570 :
3571 669 : auto initial_item = parse_enum_item ();
3572 :
3573 : // Return empty item list if no field there
3574 669 : if (!initial_item)
3575 27 : return items;
3576 :
3577 642 : items.push_back (std::move (initial_item.value ()));
3578 :
3579 3100 : while (lexer.peek_token ()->get_id () == COMMA)
3580 : {
3581 1524 : lexer.skip_token ();
3582 :
3583 3048 : if (is_end_tok (lexer.peek_token ()->get_id ()))
3584 : break;
3585 :
3586 908 : auto item = parse_enum_item ();
3587 908 : 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 908 : items.push_back (std::move (item.value ()));
3599 : }
3600 :
3601 642 : items.shrink_to_fit ();
3602 642 : return items;
3603 :
3604 : /* TODO: use template if doable (parse_non_ptr_sequence) */
3605 669 : }
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 1577 : Parser<ManagedTokenSource>::parse_enum_item ()
3612 : {
3613 : // parse outer attributes if they exist
3614 1577 : AST::AttrVec outer_attrs = parse_outer_attributes ();
3615 :
3616 : // parse visibility, which may or may not exist
3617 1577 : auto vis_res = parse_visibility ();
3618 1577 : if (!vis_res)
3619 0 : return Parse::Error::EnumVariant::make_child_error ();
3620 1577 : auto vis = vis_res.value ();
3621 :
3622 : // parse name for enum item, which is required
3623 1577 : const_TokenPtr item_name_tok = lexer.peek_token ();
3624 1577 : 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 1550 : lexer.skip_token ();
3630 3100 : Identifier item_name{item_name_tok};
3631 :
3632 : // branch based on next token
3633 1550 : const_TokenPtr t = lexer.peek_token ();
3634 1550 : switch (t->get_id ())
3635 : {
3636 558 : case LEFT_PAREN:
3637 : {
3638 : // tuple enum item
3639 558 : lexer.skip_token ();
3640 :
3641 558 : std::vector<AST::TupleField> tuple_fields;
3642 : // Might be empty tuple for unit tuple enum variant.
3643 1116 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3644 21 : tuple_fields = std::vector<AST::TupleField> ();
3645 : else
3646 537 : tuple_fields = parse_tuple_fields ();
3647 :
3648 558 : if (!skip_token (RIGHT_PAREN))
3649 : {
3650 : // skip after somewhere
3651 0 : return Parse::Error::EnumVariant::make_unfinished_tuple_variant ();
3652 : }
3653 :
3654 558 : return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
3655 : std::move (item_name), std::move (vis), std::move (tuple_fields),
3656 558 : std::move (outer_attrs), item_name_tok->get_locus ()));
3657 558 : }
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 596 : default:
3691 : // regular enum with just an identifier
3692 596 : return std::make_unique<AST::EnumItem> (std::move (item_name),
3693 : std::move (vis),
3694 : std::move (outer_attrs),
3695 596 : item_name_tok->get_locus ());
3696 : }
3697 4704 : }
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 1311 : Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
3755 : AST::AttrVec outer_attrs)
3756 : {
3757 1311 : location_t locus = lexer.peek_token ()->get_locus ();
3758 1311 : skip_token (CONST);
3759 :
3760 : /* get constant identifier - this is either a proper identifier or the _
3761 : * wildcard */
3762 1311 : const_TokenPtr ident_tok = lexer.peek_token ();
3763 : // make default identifier the underscore wildcard one
3764 1311 : std::string ident (Values::Keywords::UNDERSCORE);
3765 1311 : switch (ident_tok->get_id ())
3766 : {
3767 1303 : case IDENTIFIER:
3768 1303 : ident = ident_tok->get_str ();
3769 1303 : lexer.skip_token ();
3770 1303 : break;
3771 8 : case UNDERSCORE:
3772 : // do nothing - identifier is already "_"
3773 8 : lexer.skip_token ();
3774 8 : 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 1311 : if (!skip_token (COLON))
3787 : {
3788 0 : skip_after_semicolon ();
3789 0 : return nullptr;
3790 : }
3791 :
3792 : // parse constant type (required)
3793 1311 : std::unique_ptr<AST::Type> type = parse_type ();
3794 :
3795 : // A const with no given expression value
3796 2622 : 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 1307 : if (!skip_token (EQUAL))
3806 : {
3807 0 : skip_after_semicolon ();
3808 0 : return nullptr;
3809 : }
3810 :
3811 : // parse constant expression (required)
3812 1307 : auto expr = parse_expr ();
3813 1307 : if (!expr)
3814 1 : return nullptr;
3815 :
3816 1306 : if (!skip_token (SEMICOLON))
3817 : {
3818 : // skip somewhere?
3819 0 : return nullptr;
3820 : }
3821 :
3822 : return std::unique_ptr<AST::ConstantItem> (
3823 2612 : new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
3824 1306 : std::move (expr.value ()), std::move (outer_attrs),
3825 1306 : locus));
3826 2622 : }
3827 :
3828 : // Parses a "static item" (static storage item, with 'static lifetime).
3829 : template <typename ManagedTokenSource>
3830 : std::unique_ptr<AST::StaticItem>
3831 136 : Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
3832 : AST::AttrVec outer_attrs)
3833 : {
3834 136 : location_t locus = lexer.peek_token ()->get_locus ();
3835 136 : skip_token (STATIC_KW);
3836 :
3837 : // determine whether static item is mutable
3838 136 : bool is_mut = false;
3839 272 : if (lexer.peek_token ()->get_id () == MUT)
3840 : {
3841 19 : is_mut = true;
3842 19 : lexer.skip_token ();
3843 : }
3844 :
3845 136 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3846 136 : if (ident_tok == nullptr)
3847 1 : return nullptr;
3848 :
3849 270 : Identifier ident{ident_tok};
3850 :
3851 135 : if (!skip_token (COLON))
3852 : {
3853 1 : skip_after_semicolon ();
3854 1 : return nullptr;
3855 : }
3856 :
3857 : // parse static item type (required)
3858 134 : std::unique_ptr<AST::Type> type = parse_type ();
3859 :
3860 134 : if (!skip_token (EQUAL))
3861 : {
3862 0 : skip_after_semicolon ();
3863 0 : return nullptr;
3864 : }
3865 :
3866 : // parse static item expression (required)
3867 134 : auto expr = parse_expr ();
3868 134 : if (!expr)
3869 1 : return nullptr;
3870 :
3871 133 : if (!skip_token (SEMICOLON))
3872 : {
3873 : // skip after somewhere
3874 0 : return nullptr;
3875 : }
3876 :
3877 : return std::unique_ptr<AST::StaticItem> (
3878 266 : new AST::StaticItem (std::move (ident), is_mut, std::move (type),
3879 133 : std::move (expr.value ()), std::move (vis),
3880 133 : std::move (outer_attrs), locus));
3881 269 : }
3882 :
3883 : // Parses a trait definition item, including unsafe ones.
3884 : // also handles trait aliases
3885 : template <typename ManagedTokenSource>
3886 : std::unique_ptr<AST::VisItem>
3887 4584 : Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
3888 : AST::AttrVec outer_attrs)
3889 : {
3890 4584 : location_t locus = lexer.peek_token ()->get_locus ();
3891 4584 : bool is_unsafe = false;
3892 4584 : bool is_auto_trait = false;
3893 4584 : bool is_alias = false;
3894 :
3895 9168 : if (lexer.peek_token ()->get_id () == UNSAFE)
3896 : {
3897 85 : is_unsafe = true;
3898 85 : lexer.skip_token ();
3899 : }
3900 :
3901 9168 : if (lexer.peek_token ()->get_id () == AUTO)
3902 : {
3903 30 : is_auto_trait = true;
3904 30 : lexer.skip_token ();
3905 : }
3906 :
3907 4584 : skip_token (TRAIT);
3908 :
3909 : // parse trait name
3910 4584 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
3911 4584 : if (ident_tok == nullptr)
3912 0 : return nullptr;
3913 :
3914 9168 : Identifier ident{ident_tok};
3915 :
3916 : // parse generic parameters (if they exist)
3917 4584 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3918 : = parse_generic_params_in_angles ();
3919 :
3920 : // create placeholder type param bounds in case they don't exist
3921 4584 : std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3922 :
3923 : // this might be a trait alias
3924 9168 : if (lexer.peek_token ()->get_id () == EQUAL)
3925 : {
3926 2 : lexer.skip_token ();
3927 :
3928 2 : if (is_auto_trait)
3929 0 : rust_error_at (locus, "trait aliases cannot be %<auto%>");
3930 2 : if (is_unsafe)
3931 0 : rust_error_at (locus, "trait aliases cannot be %<unsafe%>");
3932 :
3933 2 : type_param_bounds = parse_type_param_bounds (
3934 0 : [] (TokenId id) { return id == WHERE || id == SEMICOLON; });
3935 :
3936 2 : is_alias = true;
3937 : }
3938 : // otherwise, parse type param bounds (if they exist)
3939 9164 : else if (lexer.peek_token ()->get_id () == COLON)
3940 : {
3941 671 : lexer.skip_token ();
3942 :
3943 671 : type_param_bounds = parse_type_param_bounds (
3944 95 : [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
3945 : // type_param_bounds = parse_type_param_bounds ();
3946 : }
3947 :
3948 : // parse where clause (if it exists)
3949 4584 : AST::WhereClause where_clause = parse_where_clause ();
3950 :
3951 : // if this was a trait alias, finish up
3952 4584 : if (is_alias)
3953 : {
3954 2 : if (!skip_token (SEMICOLON))
3955 0 : return nullptr;
3956 :
3957 2 : return std::make_unique<AST::TraitAlias> (std::move (ident),
3958 : std::move (generic_params),
3959 : std::move (where_clause),
3960 : std::move (type_param_bounds),
3961 : std::move (vis),
3962 2 : std::move (outer_attrs), locus);
3963 : }
3964 :
3965 4582 : if (!skip_token (LEFT_CURLY))
3966 : {
3967 0 : skip_after_end_block ();
3968 0 : return nullptr;
3969 : }
3970 :
3971 : // parse inner attrs (if they exist)
3972 4582 : AST::AttrVec inner_attrs = parse_inner_attributes ();
3973 :
3974 : // parse trait items
3975 4582 : std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
3976 :
3977 4582 : const_TokenPtr t = lexer.peek_token ();
3978 8849 : while (t->get_id () != RIGHT_CURLY)
3979 : {
3980 4267 : std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
3981 :
3982 4267 : if (trait_item == nullptr)
3983 : {
3984 0 : Error error (lexer.peek_token ()->get_locus (),
3985 : "failed to parse trait item in trait");
3986 0 : add_error (std::move (error));
3987 :
3988 0 : return nullptr;
3989 0 : }
3990 4267 : trait_items.push_back (std::move (trait_item));
3991 :
3992 4267 : t = lexer.peek_token ();
3993 : }
3994 :
3995 4582 : if (!skip_token (RIGHT_CURLY))
3996 : {
3997 : // skip after something
3998 0 : return nullptr;
3999 : }
4000 :
4001 4582 : trait_items.shrink_to_fit ();
4002 4582 : return std::unique_ptr<AST::Trait> (
4003 9164 : new AST::Trait (std::move (ident), is_unsafe, is_auto_trait,
4004 : std::move (generic_params), std::move (type_param_bounds),
4005 : std::move (where_clause), std::move (trait_items),
4006 : std::move (vis), std::move (outer_attrs),
4007 4582 : std::move (inner_attrs), locus));
4008 9166 : }
4009 :
4010 : // Parses a trait item used inside traits (not trait, the Item).
4011 : template <typename ManagedTokenSource>
4012 : std::unique_ptr<AST::AssociatedItem>
4013 4269 : Parser<ManagedTokenSource>::parse_trait_item ()
4014 : {
4015 : // parse outer attributes (if they exist)
4016 4269 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4017 :
4018 4269 : auto vis_res = parse_visibility ();
4019 4269 : if (!vis_res)
4020 0 : return nullptr;
4021 :
4022 4269 : auto vis = vis_res.value ();
4023 :
4024 : // lookahead to determine what type of trait item to parse
4025 4269 : const_TokenPtr tok = lexer.peek_token ();
4026 4269 : switch (tok->get_id ())
4027 : {
4028 0 : case SUPER:
4029 : case SELF:
4030 : case CRATE:
4031 : case DOLLAR_SIGN:
4032 : // these seem to be SimplePath tokens, so this is a macro invocation
4033 : // semi
4034 0 : return parse_macro_invocation_semi (std::move (outer_attrs));
4035 1 : case IDENTIFIER:
4036 2 : if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
4037 0 : return parse_function (std::move (vis), std::move (outer_attrs));
4038 : else
4039 2 : return parse_macro_invocation_semi (std::move (outer_attrs));
4040 911 : case TYPE:
4041 911 : return parse_trait_type (std::move (outer_attrs), vis);
4042 62 : case CONST:
4043 : // disambiguate with function qualifier
4044 124 : if (lexer.peek_token (1)->get_id () == IDENTIFIER)
4045 : {
4046 122 : return parse_trait_const (std::move (outer_attrs));
4047 : }
4048 : // else, fallthrough to function
4049 : // TODO: find out how to disable gcc "implicit fallthrough" error
4050 : gcc_fallthrough ();
4051 : case ASYNC:
4052 : case UNSAFE:
4053 : case EXTERN_KW:
4054 : case FN_KW:
4055 6592 : return parse_function (std::move (vis), std::move (outer_attrs));
4056 : default:
4057 : break;
4058 : }
4059 0 : add_error (Error (tok->get_locus (),
4060 : "unrecognised token %qs for item in trait",
4061 : tok->get_token_description ()));
4062 : // skip?
4063 0 : return nullptr;
4064 8538 : }
4065 :
4066 : // Parse a typedef trait item.
4067 : template <typename ManagedTokenSource>
4068 : std::unique_ptr<AST::TraitItemType>
4069 911 : Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
4070 : AST::Visibility vis)
4071 : {
4072 911 : location_t locus = lexer.peek_token ()->get_locus ();
4073 911 : skip_token (TYPE);
4074 :
4075 911 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4076 911 : if (ident_tok == nullptr)
4077 0 : return nullptr;
4078 :
4079 1822 : Identifier ident{ident_tok};
4080 :
4081 : // Parse optional generic parameters for GATs (Generic Associated Types)
4082 911 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
4083 1822 : if (lexer.peek_token ()->get_id () == LEFT_ANGLE)
4084 : {
4085 17 : generic_params = parse_generic_params_in_angles ();
4086 : }
4087 :
4088 911 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
4089 :
4090 : // parse optional colon
4091 1822 : if (lexer.peek_token ()->get_id () == COLON)
4092 : {
4093 69 : lexer.skip_token ();
4094 :
4095 : // parse optional type param bounds
4096 : bounds
4097 69 : = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
4098 : // bounds = parse_type_param_bounds ();
4099 : }
4100 :
4101 911 : if (!skip_token (SEMICOLON))
4102 : {
4103 : // skip?
4104 0 : return nullptr;
4105 : }
4106 :
4107 : return std::unique_ptr<AST::TraitItemType> (
4108 911 : new AST::TraitItemType (std::move (ident), std::move (generic_params),
4109 : std::move (bounds), std::move (outer_attrs), vis,
4110 911 : locus));
4111 911 : }
4112 :
4113 : // Parses a constant trait item.
4114 : template <typename ManagedTokenSource>
4115 : std::unique_ptr<AST::ConstantItem>
4116 61 : Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
4117 : {
4118 61 : location_t locus = lexer.peek_token ()->get_locus ();
4119 61 : skip_token (CONST);
4120 :
4121 : // parse constant item name
4122 61 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4123 61 : if (ident_tok == nullptr)
4124 0 : return nullptr;
4125 :
4126 122 : Identifier ident{ident_tok};
4127 :
4128 61 : if (!skip_token (COLON))
4129 : {
4130 0 : skip_after_semicolon ();
4131 0 : return nullptr;
4132 : }
4133 :
4134 : // parse constant trait item type
4135 61 : std::unique_ptr<AST::Type> type = parse_type ();
4136 :
4137 : // parse constant trait body expression, if it exists
4138 61 : std::unique_ptr<AST::Expr> const_body = nullptr;
4139 122 : if (lexer.peek_token ()->get_id () == EQUAL)
4140 : {
4141 12 : lexer.skip_token ();
4142 :
4143 : // expression must exist, so parse it
4144 12 : auto expr = parse_expr ();
4145 12 : if (!expr)
4146 0 : return nullptr;
4147 12 : const_body = std::move (expr.value ());
4148 12 : }
4149 :
4150 61 : if (!skip_token (SEMICOLON))
4151 : {
4152 : // skip after something?
4153 0 : return nullptr;
4154 : }
4155 :
4156 183 : return std::unique_ptr<AST::ConstantItem> (new AST::ConstantItem (
4157 122 : std::move (ident), AST::Visibility::create_private (), std::move (type),
4158 61 : std::move (const_body), std::move (outer_attrs), locus));
4159 122 : }
4160 :
4161 : /* Parses a struct "impl" item (both inherent impl and trait impl can be
4162 : * parsed here), */
4163 : template <typename ManagedTokenSource>
4164 : std::unique_ptr<AST::Impl>
4165 13095 : Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
4166 : AST::AttrVec outer_attrs)
4167 : {
4168 : /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
4169 : * must be a trait impl. However, this isn't enough for full disambiguation,
4170 : * so don't branch here. */
4171 13095 : location_t locus = lexer.peek_token ()->get_locus ();
4172 13095 : bool is_unsafe = false;
4173 26190 : if (lexer.peek_token ()->get_id () == UNSAFE)
4174 : {
4175 297 : lexer.skip_token ();
4176 297 : is_unsafe = true;
4177 : }
4178 :
4179 13095 : if (!skip_token (IMPL))
4180 : {
4181 0 : skip_after_next_block ();
4182 0 : return nullptr;
4183 : }
4184 :
4185 : // parse generic params (shared by trait and inherent impls)
4186 13095 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4187 : = parse_generic_params_in_angles ();
4188 :
4189 : // Again, trait impl-only feature, but optional one, so can be used for
4190 : // branching yet.
4191 13095 : bool has_exclam = false;
4192 26190 : if (lexer.peek_token ()->get_id () == EXCLAM)
4193 : {
4194 26 : lexer.skip_token ();
4195 26 : has_exclam = true;
4196 : }
4197 :
4198 : /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
4199 : * doesn't parse too much and not work. */
4200 13095 : AST::TypePath type_path = parse_type_path ();
4201 25951 : if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
4202 : {
4203 : /* cannot parse type path (or not for token next, at least), so must be
4204 : * inherent impl */
4205 :
4206 : // hacky conversion of TypePath stack object to Type pointer
4207 1568 : std::unique_ptr<AST::Type> type = nullptr;
4208 1568 : if (!type_path.is_error ())
4209 1329 : type = std::unique_ptr<AST::TypePath> (
4210 1329 : new AST::TypePath (std::move (type_path)));
4211 : else
4212 239 : type = parse_type ();
4213 :
4214 : // Type is required, so error if null
4215 1568 : if (type == nullptr)
4216 : {
4217 1 : Error error (lexer.peek_token ()->get_locus (),
4218 : "could not parse type in inherent impl");
4219 1 : add_error (std::move (error));
4220 :
4221 1 : skip_after_next_block ();
4222 1 : return nullptr;
4223 1 : }
4224 :
4225 : // parse optional where clause
4226 1567 : AST::WhereClause where_clause = parse_where_clause ();
4227 :
4228 1567 : if (!skip_token (LEFT_CURLY))
4229 : {
4230 : // TODO: does this still skip properly?
4231 0 : skip_after_end_block ();
4232 0 : return nullptr;
4233 : }
4234 :
4235 : // parse inner attributes (optional)
4236 1567 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4237 :
4238 : // parse inherent impl items
4239 1567 : std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
4240 :
4241 1567 : const_TokenPtr t = lexer.peek_token ();
4242 6790 : while (t->get_id () != RIGHT_CURLY)
4243 : {
4244 5233 : std::unique_ptr<AST::AssociatedItem> impl_item
4245 : = parse_inherent_impl_item ();
4246 :
4247 5233 : if (impl_item == nullptr)
4248 : {
4249 10 : Error error (
4250 10 : lexer.peek_token ()->get_locus (),
4251 : "failed to parse inherent impl item in inherent impl");
4252 10 : add_error (std::move (error));
4253 :
4254 10 : return nullptr;
4255 10 : }
4256 :
4257 5223 : impl_items.push_back (std::move (impl_item));
4258 :
4259 5223 : t = lexer.peek_token ();
4260 : }
4261 :
4262 1557 : if (!skip_token (RIGHT_CURLY))
4263 : {
4264 : // skip somewhere
4265 0 : return nullptr;
4266 : }
4267 :
4268 : // DEBUG
4269 1557 : rust_debug ("successfully parsed inherent impl");
4270 :
4271 1557 : impl_items.shrink_to_fit ();
4272 :
4273 1557 : return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
4274 : std::move (impl_items), std::move (generic_params), std::move (type),
4275 : std::move (where_clause), std::move (vis), std::move (inner_attrs),
4276 1557 : std::move (outer_attrs), locus));
4277 1568 : }
4278 : else
4279 : {
4280 : // type path must both be valid and next token is for, so trait impl
4281 11527 : if (!skip_token (FOR))
4282 : {
4283 0 : skip_after_next_block ();
4284 0 : return nullptr;
4285 : }
4286 :
4287 : // parse type
4288 11527 : std::unique_ptr<AST::Type> type = parse_type ();
4289 : // ensure type is included as it is required
4290 11527 : if (type == nullptr)
4291 : {
4292 0 : Error error (lexer.peek_token ()->get_locus (),
4293 : "could not parse type in trait impl");
4294 0 : add_error (std::move (error));
4295 :
4296 0 : skip_after_next_block ();
4297 0 : return nullptr;
4298 0 : }
4299 :
4300 : // parse optional where clause
4301 11527 : AST::WhereClause where_clause = parse_where_clause ();
4302 :
4303 11527 : if (!skip_token (LEFT_CURLY))
4304 : {
4305 : // TODO: does this still skip properly?
4306 0 : skip_after_end_block ();
4307 0 : return nullptr;
4308 : }
4309 :
4310 : // parse inner attributes (optional)
4311 11527 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4312 :
4313 : // parse trait impl items
4314 11527 : std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
4315 :
4316 11527 : const_TokenPtr t = lexer.peek_token ();
4317 27343 : while (t->get_id () != RIGHT_CURLY)
4318 : {
4319 15819 : std::unique_ptr<AST::AssociatedItem> impl_item
4320 : = parse_trait_impl_item ();
4321 :
4322 15819 : if (impl_item == nullptr)
4323 : {
4324 3 : Error error (lexer.peek_token ()->get_locus (),
4325 : "failed to parse trait impl item in trait impl");
4326 3 : add_error (std::move (error));
4327 :
4328 3 : return nullptr;
4329 3 : }
4330 :
4331 15816 : impl_items.push_back (std::move (impl_item));
4332 :
4333 15816 : t = lexer.peek_token ();
4334 :
4335 : // DEBUG
4336 15816 : rust_debug ("successfully parsed a trait impl item");
4337 : }
4338 : // DEBUG
4339 11524 : rust_debug ("successfully finished trait impl items");
4340 :
4341 11524 : if (!skip_token (RIGHT_CURLY))
4342 : {
4343 : // skip somewhere
4344 0 : return nullptr;
4345 : }
4346 :
4347 : // DEBUG
4348 11524 : rust_debug ("successfully parsed trait impl");
4349 :
4350 11524 : impl_items.shrink_to_fit ();
4351 :
4352 11524 : return std::unique_ptr<AST::TraitImpl> (
4353 23048 : new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
4354 : std::move (impl_items), std::move (generic_params),
4355 : std::move (type), std::move (where_clause),
4356 : std::move (vis), std::move (inner_attrs),
4357 11524 : std::move (outer_attrs), locus));
4358 11527 : }
4359 13095 : }
4360 :
4361 : // Parses a single inherent impl item (item inside an inherent impl block).
4362 : template <typename ManagedTokenSource>
4363 : std::unique_ptr<AST::AssociatedItem>
4364 7239 : Parser<ManagedTokenSource>::parse_inherent_impl_item ()
4365 : {
4366 : // parse outer attributes (if they exist)
4367 7239 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4368 :
4369 : // TODO: cleanup - currently an unreadable mess
4370 :
4371 : // branch on next token:
4372 7239 : const_TokenPtr t = lexer.peek_token ();
4373 7239 : switch (t->get_id ())
4374 : {
4375 1091 : case IDENTIFIER:
4376 : // FIXME: Arthur: Do we need to some lookahead here?
4377 2182 : return parse_macro_invocation_semi (outer_attrs);
4378 5262 : case SUPER:
4379 : case SELF:
4380 : case CRATE:
4381 : case PUB:
4382 : {
4383 : // visibility, so not a macro invocation semi - must be constant,
4384 : // function, or method
4385 5262 : auto vis_res = parse_visibility ();
4386 5262 : if (!vis_res)
4387 0 : return nullptr;
4388 5262 : auto vis = vis_res.value ();
4389 :
4390 : // TODO: is a recursive call to parse_inherent_impl_item better?
4391 10524 : switch (lexer.peek_token ()->get_id ())
4392 : {
4393 2900 : case EXTERN_KW:
4394 : case UNSAFE:
4395 : case FN_KW:
4396 : // function or method
4397 5800 : return parse_inherent_impl_function_or_method (std::move (vis),
4398 : std::move (
4399 2900 : outer_attrs));
4400 2362 : case CONST:
4401 : // lookahead to resolve production - could be function/method or
4402 : // const item
4403 2362 : t = lexer.peek_token (1);
4404 :
4405 2362 : switch (t->get_id ())
4406 : {
4407 102 : case IDENTIFIER:
4408 : case UNDERSCORE:
4409 204 : return parse_const_item (std::move (vis),
4410 102 : std::move (outer_attrs));
4411 2260 : case UNSAFE:
4412 : case EXTERN_KW:
4413 : case FN_KW:
4414 4520 : return parse_inherent_impl_function_or_method (std::move (vis),
4415 : std::move (
4416 2260 : outer_attrs));
4417 0 : default:
4418 0 : add_error (Error (t->get_locus (),
4419 : "unexpected token %qs in some sort of const "
4420 : "item in inherent impl",
4421 : t->get_token_description ()));
4422 :
4423 0 : lexer.skip_token (1); // TODO: is this right thing to do?
4424 0 : return nullptr;
4425 : }
4426 0 : default:
4427 0 : add_error (
4428 0 : Error (t->get_locus (),
4429 : "unrecognised token %qs for item in inherent impl",
4430 : t->get_token_description ()));
4431 : // skip?
4432 0 : return nullptr;
4433 : }
4434 10524 : }
4435 830 : case ASYNC:
4436 : case EXTERN_KW:
4437 : case UNSAFE:
4438 : case FN_KW:
4439 : // function or method
4440 830 : return parse_inherent_impl_function_or_method (
4441 830 : AST::Visibility::create_private (), std::move (outer_attrs));
4442 56 : case CONST:
4443 : /* lookahead to resolve production - could be function/method or const
4444 : * item */
4445 56 : t = lexer.peek_token (1);
4446 :
4447 56 : switch (t->get_id ())
4448 : {
4449 43 : case IDENTIFIER:
4450 : case UNDERSCORE:
4451 86 : return parse_const_item (AST::Visibility::create_private (),
4452 43 : std::move (outer_attrs));
4453 13 : case UNSAFE:
4454 : case EXTERN_KW:
4455 : case FN_KW:
4456 13 : return parse_inherent_impl_function_or_method (
4457 13 : AST::Visibility::create_private (), std::move (outer_attrs));
4458 0 : default:
4459 0 : add_error (Error (t->get_locus (),
4460 : "unexpected token %qs in some sort of const item "
4461 : "in inherent impl",
4462 : t->get_token_description ()));
4463 :
4464 0 : lexer.skip_token (1); // TODO: is this right thing to do?
4465 0 : return nullptr;
4466 : }
4467 : rust_unreachable ();
4468 0 : default:
4469 0 : add_error (Error (t->get_locus (),
4470 : "unrecognised token %qs for item in inherent impl",
4471 : t->get_token_description ()));
4472 :
4473 : // skip?
4474 0 : return nullptr;
4475 : }
4476 7239 : }
4477 :
4478 : /* For internal use only by parse_inherent_impl_item() - splits giant method
4479 : * into smaller ones and prevents duplication of logic. Strictly, this parses
4480 : * a function or method item inside an inherent impl item block. */
4481 : // TODO: make this a templated function with "return type" as type param -
4482 : // InherentImplItem is this specialisation of the template while TraitImplItem
4483 : // will be the other.
4484 : template <typename ManagedTokenSource>
4485 : std::unique_ptr<AST::AssociatedItem>
4486 6003 : Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
4487 : AST::Visibility vis, AST::AttrVec outer_attrs)
4488 : {
4489 6003 : location_t locus = lexer.peek_token ()->get_locus ();
4490 : // parse function or method qualifiers
4491 6003 : auto qualifiers = parse_function_qualifiers ();
4492 6003 : if (!qualifiers)
4493 0 : return nullptr;
4494 :
4495 6003 : skip_token (FN_KW);
4496 :
4497 : // parse function or method name
4498 6003 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4499 6003 : if (ident_tok == nullptr)
4500 7 : return nullptr;
4501 :
4502 11992 : Identifier ident{ident_tok};
4503 :
4504 : // parse generic params
4505 5996 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4506 : = parse_generic_params_in_angles ();
4507 :
4508 5996 : if (!skip_token (LEFT_PAREN))
4509 : {
4510 : // skip after somewhere?
4511 0 : return nullptr;
4512 : }
4513 :
4514 : // now for function vs method disambiguation - method has opening "self"
4515 : // param
4516 5996 : auto initial_param = parse_self_param ();
4517 :
4518 5996 : if (!initial_param.has_value ()
4519 5996 : && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
4520 3 : return nullptr;
4521 :
4522 : /* FIXME: ensure that self param doesn't accidently consume tokens for a
4523 : * function one idea is to lookahead up to 4 tokens to see whether self is
4524 : * one of them */
4525 5993 : bool is_method = false;
4526 5993 : if (initial_param.has_value ())
4527 : {
4528 4436 : if ((*initial_param)->is_self ())
4529 : is_method = true;
4530 :
4531 : /* skip comma so function and method regular params can be parsed in
4532 : * same way */
4533 8872 : if (lexer.peek_token ()->get_id () == COMMA)
4534 2593 : lexer.skip_token ();
4535 : }
4536 :
4537 : // parse trait function params
4538 5993 : std::vector<std::unique_ptr<AST::Param>> function_params
4539 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
4540 :
4541 5993 : if (initial_param.has_value ())
4542 4436 : function_params.insert (function_params.begin (),
4543 4436 : std::move (*initial_param));
4544 :
4545 5993 : if (!skip_token (RIGHT_PAREN))
4546 : {
4547 0 : skip_after_end_block ();
4548 0 : return nullptr;
4549 : }
4550 :
4551 : // parse return type (optional)
4552 5993 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
4553 :
4554 : // parse where clause (optional)
4555 5993 : AST::WhereClause where_clause = parse_where_clause ();
4556 :
4557 5993 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
4558 11986 : if (lexer.peek_token ()->get_id () == SEMICOLON)
4559 2 : lexer.skip_token ();
4560 : else
4561 : {
4562 5991 : auto result = parse_block_expr ();
4563 :
4564 5991 : if (!result)
4565 : {
4566 0 : Error error (
4567 0 : lexer.peek_token ()->get_locus (),
4568 : "could not parse definition in inherent impl %s definition",
4569 : is_method ? "method" : "function");
4570 0 : add_error (std::move (error));
4571 :
4572 0 : skip_after_end_block ();
4573 0 : return nullptr;
4574 0 : }
4575 5991 : body = std::move (result.value ());
4576 5991 : }
4577 :
4578 5993 : return std::unique_ptr<AST::Function> (
4579 23970 : new AST::Function (std::move (ident), std::move (qualifiers.value ()),
4580 : std::move (generic_params), std::move (function_params),
4581 : std::move (return_type), std::move (where_clause),
4582 : std::move (body), std::move (vis),
4583 5993 : std::move (outer_attrs), locus));
4584 17992 : }
4585 :
4586 : // Parses a single trait impl item (item inside a trait impl block).
4587 : template <typename ManagedTokenSource>
4588 : std::unique_ptr<AST::AssociatedItem>
4589 16072 : Parser<ManagedTokenSource>::parse_trait_impl_item ()
4590 : {
4591 : // parse outer attributes (if they exist)
4592 16072 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4593 :
4594 16072 : auto vis_res = parse_visibility ();
4595 16072 : if (!vis_res)
4596 0 : return nullptr;
4597 16072 : auto visibility = vis_res.value ();
4598 :
4599 : // branch on next token:
4600 16072 : const_TokenPtr t = lexer.peek_token ();
4601 16072 : switch (t->get_id ())
4602 : {
4603 0 : case SUPER:
4604 : case SELF:
4605 : case CRATE:
4606 : case DOLLAR_SIGN:
4607 : // these seem to be SimplePath tokens, so this is a macro invocation
4608 : // semi
4609 0 : return parse_macro_invocation_semi (std::move (outer_attrs));
4610 147 : case IDENTIFIER:
4611 294 : if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
4612 148 : return parse_trait_impl_function_or_method (visibility,
4613 74 : std::move (outer_attrs));
4614 : else
4615 146 : return parse_macro_invocation_semi (std::move (outer_attrs));
4616 4255 : case TYPE:
4617 8510 : return parse_type_alias (visibility, std::move (outer_attrs));
4618 11593 : case EXTERN_KW:
4619 : case UNSAFE:
4620 : case FN_KW:
4621 : // function or method
4622 23186 : return parse_trait_impl_function_or_method (visibility,
4623 11593 : std::move (outer_attrs));
4624 1 : case ASYNC:
4625 2 : return parse_async_item (visibility, std::move (outer_attrs));
4626 76 : case CONST:
4627 : // lookahead to resolve production - could be function/method or const
4628 : // item
4629 76 : t = lexer.peek_token (1);
4630 :
4631 76 : switch (t->get_id ())
4632 : {
4633 75 : case IDENTIFIER:
4634 : case UNDERSCORE:
4635 150 : return parse_const_item (visibility, std::move (outer_attrs));
4636 1 : case UNSAFE:
4637 : case EXTERN_KW:
4638 : case FN_KW:
4639 2 : return parse_trait_impl_function_or_method (visibility,
4640 1 : std::move (outer_attrs));
4641 0 : default:
4642 0 : add_error (Error (
4643 : t->get_locus (),
4644 : "unexpected token %qs in some sort of const item in trait impl",
4645 : t->get_token_description ()));
4646 :
4647 0 : lexer.skip_token (1); // TODO: is this right thing to do?
4648 0 : return nullptr;
4649 : }
4650 : rust_unreachable ();
4651 : default:
4652 : break;
4653 : }
4654 0 : add_error (Error (t->get_locus (),
4655 : "unrecognised token %qs for item in trait impl",
4656 : t->get_token_description ()));
4657 :
4658 : // skip?
4659 0 : return nullptr;
4660 32144 : }
4661 :
4662 : /* For internal use only by parse_trait_impl_item() - splits giant method into
4663 : * smaller ones and prevents duplication of logic. Strictly, this parses a
4664 : * function or method item inside a trait impl item block. */
4665 : template <typename ManagedTokenSource>
4666 : std::unique_ptr<AST::AssociatedItem>
4667 11668 : Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
4668 : AST::Visibility vis, AST::AttrVec outer_attrs)
4669 : {
4670 : // this shares virtually all logic with
4671 : // parse_inherent_impl_function_or_method
4672 : // - template?
4673 11668 : location_t locus = lexer.peek_token ()->get_locus ();
4674 :
4675 : // parse function or method qualifiers
4676 11668 : auto qualifiers = parse_function_qualifiers ();
4677 11668 : if (!qualifiers)
4678 2 : return nullptr;
4679 :
4680 11666 : skip_token (FN_KW);
4681 :
4682 : // parse function or method name
4683 11666 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4684 11666 : if (ident_tok == nullptr)
4685 : {
4686 0 : return nullptr;
4687 : }
4688 23332 : Identifier ident{ident_tok};
4689 :
4690 : // DEBUG:
4691 11666 : rust_debug (
4692 : "about to start parsing generic params in trait impl function or method");
4693 :
4694 : // parse generic params
4695 11666 : std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4696 : = parse_generic_params_in_angles ();
4697 :
4698 : // DEBUG:
4699 11666 : rust_debug (
4700 : "finished parsing generic params in trait impl function or method");
4701 :
4702 11666 : if (!skip_token (LEFT_PAREN))
4703 : {
4704 : // skip after somewhere?
4705 0 : return nullptr;
4706 : }
4707 :
4708 : // now for function vs method disambiguation - method has opening "self"
4709 : // param
4710 11666 : auto initial_param = parse_self_param ();
4711 :
4712 11666 : if (!initial_param.has_value ()
4713 11666 : && initial_param.error ().kind != Parse::Error::Self::Kind::NOT_SELF)
4714 0 : return nullptr;
4715 :
4716 : // FIXME: ensure that self param doesn't accidently consume tokens for a
4717 : // function
4718 11666 : bool is_method = false;
4719 11666 : if (initial_param.has_value ())
4720 : {
4721 10507 : if ((*initial_param)->is_self ())
4722 : is_method = true;
4723 :
4724 : // skip comma so function and method regular params can be parsed in
4725 : // same way
4726 21014 : if (lexer.peek_token ()->get_id () == COMMA)
4727 : {
4728 7438 : lexer.skip_token ();
4729 : }
4730 :
4731 : // DEBUG
4732 10507 : rust_debug ("successfully parsed self param in method trait impl item");
4733 : }
4734 :
4735 : // DEBUG
4736 11666 : rust_debug (
4737 : "started to parse function params in function or method trait impl item");
4738 :
4739 : // parse trait function params (only if next token isn't right paren)
4740 11666 : std::vector<std::unique_ptr<AST::Param>> function_params;
4741 23332 : if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
4742 : {
4743 : function_params
4744 8355 : = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
4745 :
4746 8355 : if (function_params.empty ())
4747 : {
4748 0 : Error error (
4749 0 : lexer.peek_token ()->get_locus (),
4750 : "failed to parse function params in trait impl %s definition",
4751 : is_method ? "method" : "function");
4752 0 : add_error (std::move (error));
4753 :
4754 0 : skip_after_next_block ();
4755 0 : return nullptr;
4756 0 : }
4757 : }
4758 :
4759 11666 : if (initial_param.has_value ())
4760 10507 : function_params.insert (function_params.begin (),
4761 10507 : std::move (*initial_param));
4762 :
4763 : // DEBUG
4764 11666 : rust_debug ("successfully parsed function params in function or method "
4765 : "trait impl item");
4766 :
4767 11666 : if (!skip_token (RIGHT_PAREN))
4768 : {
4769 0 : skip_after_next_block ();
4770 0 : return nullptr;
4771 : }
4772 :
4773 : // parse return type (optional)
4774 11666 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
4775 :
4776 : // DEBUG
4777 11666 : rust_debug (
4778 : "successfully parsed return type in function or method trait impl item");
4779 :
4780 : // parse where clause (optional)
4781 11666 : AST::WhereClause where_clause = parse_where_clause ();
4782 :
4783 : // DEBUG
4784 11666 : rust_debug (
4785 : "successfully parsed where clause in function or method trait impl item");
4786 :
4787 : // parse function definition (in block) - semicolon not allowed
4788 11666 : tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
4789 :
4790 23332 : if (lexer.peek_token ()->get_id () == SEMICOLON)
4791 1 : lexer.skip_token ();
4792 : else
4793 : {
4794 11665 : auto result = parse_block_expr ();
4795 11665 : if (!result)
4796 : {
4797 1 : Error error (lexer.peek_token ()->get_locus (),
4798 : "could not parse definition in trait impl %s definition",
4799 : is_method ? "method" : "function");
4800 1 : add_error (std::move (error));
4801 :
4802 1 : skip_after_end_block ();
4803 1 : return nullptr;
4804 1 : }
4805 11664 : body = std::move (result.value ());
4806 11665 : }
4807 :
4808 11665 : return std::unique_ptr<AST::Function> (
4809 46659 : new AST::Function (std::move (ident), std::move (qualifiers.value ()),
4810 : std::move (generic_params), std::move (function_params),
4811 : std::move (return_type), std::move (where_clause),
4812 : std::move (body), std::move (vis),
4813 11665 : std::move (outer_attrs), locus));
4814 34998 : }
4815 :
4816 : // Parses an extern block of declarations.
4817 : template <typename ManagedTokenSource>
4818 : std::unique_ptr<AST::ExternBlock>
4819 1787 : Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
4820 : AST::AttrVec outer_attrs)
4821 : {
4822 1787 : location_t locus = lexer.peek_token ()->get_locus ();
4823 1787 : skip_token (EXTERN_KW);
4824 :
4825 : // detect optional abi name
4826 1787 : std::string abi;
4827 1787 : const_TokenPtr next_tok = lexer.peek_token ();
4828 1787 : if (next_tok->get_id () == STRING_LITERAL)
4829 : {
4830 1786 : lexer.skip_token ();
4831 1786 : abi = next_tok->get_str ();
4832 : }
4833 :
4834 1787 : if (!skip_token (LEFT_CURLY))
4835 : {
4836 0 : skip_after_end_block ();
4837 0 : return nullptr;
4838 : }
4839 :
4840 1787 : AST::AttrVec inner_attrs = parse_inner_attributes ();
4841 :
4842 : // parse declarations inside extern block
4843 1787 : std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
4844 :
4845 1787 : const_TokenPtr t = lexer.peek_token ();
4846 5341 : while (t->get_id () != RIGHT_CURLY)
4847 : {
4848 3555 : std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
4849 :
4850 3555 : if (extern_item == nullptr)
4851 : {
4852 1 : Error error (t->get_locus (),
4853 : "failed to parse external item despite not reaching "
4854 : "end of extern block");
4855 1 : add_error (std::move (error));
4856 :
4857 1 : return nullptr;
4858 1 : }
4859 :
4860 3554 : extern_items.push_back (std::move (extern_item));
4861 :
4862 3554 : t = lexer.peek_token ();
4863 : }
4864 :
4865 1786 : if (!skip_token (RIGHT_CURLY))
4866 : {
4867 : // skip somewhere
4868 0 : return nullptr;
4869 : }
4870 :
4871 1786 : extern_items.shrink_to_fit ();
4872 :
4873 : return std::unique_ptr<AST::ExternBlock> (
4874 1786 : new AST::ExternBlock (std::move (abi), std::move (extern_items),
4875 : std::move (vis), std::move (inner_attrs),
4876 1786 : std::move (outer_attrs), locus));
4877 3574 : }
4878 :
4879 : // Parses a single extern block item (static or function declaration).
4880 : template <typename ManagedTokenSource>
4881 : std::unique_ptr<AST::ExternalItem>
4882 3558 : Parser<ManagedTokenSource>::parse_external_item ()
4883 : {
4884 : // parse optional outer attributes
4885 3558 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4886 :
4887 3558 : location_t locus = lexer.peek_token ()->get_locus ();
4888 :
4889 : // parse optional visibility
4890 3558 : auto vis_res = parse_visibility ();
4891 3558 : if (!vis_res)
4892 0 : return nullptr;
4893 3558 : auto vis = vis_res.value ();
4894 :
4895 3558 : const_TokenPtr t = lexer.peek_token ();
4896 3558 : switch (t->get_id ())
4897 : {
4898 2 : case IDENTIFIER:
4899 4 : return parse_macro_invocation_semi (outer_attrs);
4900 1 : case STATIC_KW:
4901 : {
4902 : // parse extern static item
4903 1 : lexer.skip_token ();
4904 :
4905 : // parse mut (optional)
4906 1 : bool has_mut = false;
4907 2 : if (lexer.peek_token ()->get_id () == MUT)
4908 : {
4909 0 : lexer.skip_token ();
4910 0 : has_mut = true;
4911 : }
4912 :
4913 : // parse identifier
4914 1 : const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4915 1 : if (ident_tok == nullptr)
4916 : {
4917 0 : skip_after_semicolon ();
4918 0 : return nullptr;
4919 : }
4920 2 : Identifier ident{ident_tok};
4921 :
4922 1 : if (!skip_token (COLON))
4923 : {
4924 0 : skip_after_semicolon ();
4925 0 : return nullptr;
4926 : }
4927 :
4928 : // parse type (required)
4929 1 : std::unique_ptr<AST::Type> type = parse_type ();
4930 1 : if (type == nullptr)
4931 : {
4932 0 : Error error (lexer.peek_token ()->get_locus (),
4933 : "failed to parse type in external static item");
4934 0 : add_error (std::move (error));
4935 :
4936 0 : skip_after_semicolon ();
4937 0 : return nullptr;
4938 0 : }
4939 :
4940 1 : if (!skip_token (SEMICOLON))
4941 : {
4942 : // skip after somewhere?
4943 0 : return nullptr;
4944 : }
4945 :
4946 1 : return std::unique_ptr<AST::ExternalStaticItem> (
4947 2 : new AST::ExternalStaticItem (std::move (ident), std::move (type),
4948 : has_mut, std::move (vis),
4949 1 : std::move (outer_attrs), locus));
4950 3 : }
4951 3547 : case FN_KW:
4952 7094 : return parse_function (std::move (vis), std::move (outer_attrs), true);
4953 :
4954 8 : case TYPE:
4955 8 : return parse_external_type_item (std::move (vis),
4956 8 : std::move (outer_attrs));
4957 0 : default:
4958 : // error
4959 0 : add_error (
4960 0 : Error (t->get_locus (),
4961 : "unrecognised token %qs in extern block item declaration",
4962 : t->get_token_description ()));
4963 :
4964 0 : skip_after_semicolon ();
4965 0 : return nullptr;
4966 : }
4967 7116 : }
4968 :
4969 : // Parses a statement (will further disambiguate any statement).
4970 : template <typename ManagedTokenSource>
4971 : std::unique_ptr<AST::Stmt>
4972 1087 : Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
4973 : {
4974 : // quick exit for empty statement
4975 : // FIXME: Can we have empty statements without semicolons? Just nothing?
4976 1087 : const_TokenPtr t = lexer.peek_token ();
4977 1087 : if (t->get_id () == SEMICOLON)
4978 : {
4979 30 : lexer.skip_token ();
4980 30 : return std::unique_ptr<AST::EmptyStmt> (
4981 30 : new AST::EmptyStmt (t->get_locus ()));
4982 : }
4983 :
4984 : // parse outer attributes
4985 1057 : AST::AttrVec outer_attrs = parse_outer_attributes ();
4986 :
4987 : // parsing this will be annoying because of the many different possibilities
4988 : /* best may be just to copy paste in parse_item switch, and failing that try
4989 : * to parse outer attributes, and then pass them in to either a let
4990 : * statement or (fallback) expression statement. */
4991 : // FIXME: think of a way to do this without such a large switch?
4992 1057 : t = lexer.peek_token ();
4993 1057 : switch (t->get_id ())
4994 : {
4995 227 : case LET:
4996 : // let statement
4997 227 : return parse_let_stmt (std::move (outer_attrs), restrictions);
4998 186 : case PUB:
4999 : case MOD:
5000 : case EXTERN_KW:
5001 : case USE:
5002 : case FN_KW:
5003 : case TYPE:
5004 : case STRUCT_KW:
5005 : case ENUM_KW:
5006 : case CONST:
5007 : case STATIC_KW:
5008 : case AUTO:
5009 : case TRAIT:
5010 : case IMPL:
5011 : case MACRO:
5012 : /* TODO: implement union keyword but not really because of
5013 : * context-dependence crappy hack way to parse a union written below to
5014 : * separate it from the good code. */
5015 : // case UNION:
5016 : case UNSAFE: // maybe - unsafe traits are a thing
5017 : /* if any of these (should be all possible VisItem prefixes), parse a
5018 : * VisItem can't parse item because would require reparsing outer
5019 : * attributes */
5020 : // may also be unsafe block
5021 372 : if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
5022 : {
5023 1 : return parse_expr_stmt (std::move (outer_attrs), restrictions);
5024 : }
5025 : else
5026 : {
5027 185 : return parse_vis_item (std::move (outer_attrs));
5028 : }
5029 : break;
5030 : // crappy hack to do union "keyword"
5031 267 : case IDENTIFIER:
5032 267 : if (t->get_str () == Values::WeakKeywords::UNION
5033 267 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
5034 : {
5035 0 : return parse_vis_item (std::move (outer_attrs));
5036 : // or should this go straight to parsing union?
5037 : }
5038 534 : else if (is_macro_rules_def (t))
5039 : {
5040 : // macro_rules! macro item
5041 2 : return parse_macro_rules_def (std::move (outer_attrs));
5042 : }
5043 : gcc_fallthrough ();
5044 : // TODO: find out how to disable gcc "implicit fallthrough" warning
5045 : default:
5046 : // fallback: expression statement
5047 642 : return parse_expr_stmt (std::move (outer_attrs), restrictions);
5048 : break;
5049 : }
5050 1057 : }
5051 :
5052 : // Parses a let statement.
5053 : template <typename ManagedTokenSource>
5054 : std::unique_ptr<AST::LetStmt>
5055 24710 : Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
5056 : ParseRestrictions restrictions)
5057 : {
5058 24710 : location_t locus = lexer.peek_token ()->get_locus ();
5059 24710 : skip_token (LET);
5060 :
5061 : // parse pattern (required)
5062 24710 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
5063 24710 : if (pattern == nullptr)
5064 : {
5065 0 : Error error (lexer.peek_token ()->get_locus (),
5066 : "failed to parse pattern in let statement");
5067 0 : add_error (std::move (error));
5068 :
5069 0 : skip_after_semicolon ();
5070 0 : return nullptr;
5071 0 : }
5072 :
5073 : // parse type declaration (optional)
5074 24710 : std::unique_ptr<AST::Type> type = nullptr;
5075 49420 : if (lexer.peek_token ()->get_id () == COLON)
5076 : {
5077 : // must have a type declaration
5078 2712 : lexer.skip_token ();
5079 :
5080 2712 : type = parse_type ();
5081 2712 : if (type == nullptr)
5082 : {
5083 0 : Error error (lexer.peek_token ()->get_locus (),
5084 : "failed to parse type in let statement");
5085 0 : add_error (std::move (error));
5086 :
5087 0 : skip_after_semicolon ();
5088 0 : return nullptr;
5089 0 : }
5090 : }
5091 :
5092 : // parse expression to set variable to (optional)
5093 24710 : std::unique_ptr<AST::Expr> expr = nullptr;
5094 49420 : if (lexer.peek_token ()->get_id () == EQUAL)
5095 : {
5096 : // must have an expression
5097 23576 : lexer.skip_token ();
5098 :
5099 23576 : auto expr_res = parse_expr ();
5100 23576 : if (!expr_res)
5101 : {
5102 22 : skip_after_semicolon ();
5103 22 : return nullptr;
5104 : }
5105 23554 : expr = std::move (expr_res.value ());
5106 23576 : }
5107 :
5108 24688 : tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
5109 24688 : if (maybe_skip_token (ELSE))
5110 : {
5111 5 : auto block_expr = parse_block_expr ();
5112 5 : if (block_expr)
5113 : else_expr = tl::optional<std::unique_ptr<AST::Expr>>{
5114 10 : std::move (block_expr.value ())};
5115 : else
5116 : else_expr = tl::nullopt;
5117 5 : }
5118 :
5119 24688 : if (restrictions.consume_semi)
5120 : {
5121 : // `stmt` macro variables are parsed without a semicolon, but should be
5122 : // parsed as a full statement when interpolated. This should be handled
5123 : // by having the interpolated statement be distinguishable from normal
5124 : // tokens, e.g. by NT tokens.
5125 24543 : if (restrictions.allow_close_after_expr_stmt)
5126 82 : maybe_skip_token (SEMICOLON);
5127 24461 : else if (!skip_token (SEMICOLON))
5128 1 : return nullptr;
5129 : }
5130 :
5131 : return std::unique_ptr<AST::LetStmt> (
5132 49379 : new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
5133 24687 : std::move (else_expr), std::move (outer_attrs), locus));
5134 24710 : }
5135 :
5136 : template <typename ManagedTokenSource>
5137 : tl::optional<AST::GenericArg>
5138 23210 : Parser<ManagedTokenSource>::parse_generic_arg ()
5139 : {
5140 23210 : auto tok = lexer.peek_token ();
5141 23210 : std::unique_ptr<AST::Expr> expr = nullptr;
5142 :
5143 23210 : switch (tok->get_id ())
5144 : {
5145 17835 : case IDENTIFIER:
5146 : {
5147 : // This is a bit of a weird situation: With an identifier token, we
5148 : // could either have a valid type or a macro (FIXME: anything else?). So
5149 : // we need one bit of lookahead to differentiate if this is really
5150 17835 : auto next_tok = lexer.peek_token (1);
5151 17835 : if (next_tok->get_id () == LEFT_ANGLE
5152 16731 : || next_tok->get_id () == SCOPE_RESOLUTION
5153 34114 : || next_tok->get_id () == EXCLAM)
5154 : {
5155 1564 : auto type = parse_type ();
5156 1564 : if (type)
5157 1564 : return AST::GenericArg::create_type (std::move (type));
5158 : else
5159 0 : return tl::nullopt;
5160 1564 : }
5161 16271 : else if (next_tok->get_id () == COLON)
5162 : {
5163 0 : lexer.skip_token (); // skip ident
5164 0 : lexer.skip_token (); // skip colon
5165 :
5166 0 : auto tok = lexer.peek_token ();
5167 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5168 : = parse_type_param_bounds ();
5169 :
5170 0 : auto type = std::unique_ptr<AST::TraitObjectType> (
5171 0 : new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
5172 : false));
5173 0 : if (type)
5174 0 : return AST::GenericArg::create_type (std::move (type));
5175 : else
5176 : return tl::nullopt;
5177 0 : }
5178 16271 : lexer.skip_token ();
5179 65084 : return AST::GenericArg::create_ambiguous (tok->get_str (),
5180 16271 : tok->get_locus ());
5181 20011 : }
5182 23 : case LEFT_CURLY:
5183 : {
5184 23 : auto res = parse_block_expr ();
5185 23 : if (res)
5186 23 : expr = std::move (res.value ());
5187 : else
5188 0 : return tl::nullopt;
5189 0 : }
5190 23 : break;
5191 92 : case MINUS:
5192 : case STRING_LITERAL:
5193 : case CHAR_LITERAL:
5194 : case INT_LITERAL:
5195 : case FLOAT_LITERAL:
5196 : case TRUE_LITERAL:
5197 : case FALSE_LITERAL:
5198 : {
5199 92 : auto res = parse_literal_expr ();
5200 92 : if (res)
5201 92 : expr = std::move (res.value ());
5202 : else
5203 0 : return tl::nullopt;
5204 0 : }
5205 92 : break;
5206 : // FIXME: Because of this, error reporting is garbage for const generic
5207 : // parameter's default values
5208 5260 : default:
5209 : {
5210 5260 : auto type = parse_type ();
5211 : // FIXME: Find a better way to do this?
5212 5260 : if (type)
5213 5259 : return AST::GenericArg::create_type (std::move (type));
5214 : else
5215 1 : return tl::nullopt;
5216 5260 : }
5217 : }
5218 :
5219 115 : if (!expr)
5220 0 : return tl::nullopt;
5221 :
5222 115 : return AST::GenericArg::create_const (std::move (expr));
5223 23210 : }
5224 :
5225 : // Parses the generic arguments in each path segment.
5226 : template <typename ManagedTokenSource>
5227 : AST::GenericArgs
5228 22593 : Parser<ManagedTokenSource>::parse_path_generic_args ()
5229 : {
5230 45186 : if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
5231 21 : lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
5232 :
5233 22593 : if (!skip_token (LEFT_ANGLE))
5234 : {
5235 : // skip after somewhere?
5236 0 : return AST::GenericArgs::create_empty ();
5237 : }
5238 :
5239 : // We need to parse all lifetimes, then parse types and const generics in
5240 : // any order.
5241 :
5242 : // try to parse lifetimes first
5243 22593 : std::vector<AST::Lifetime> lifetime_args;
5244 :
5245 22593 : const_TokenPtr t = lexer.peek_token ();
5246 22593 : location_t locus = t->get_locus ();
5247 46096 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5248 : {
5249 23503 : auto lifetime = parse_lifetime (false);
5250 23503 : if (!lifetime)
5251 : {
5252 : // not necessarily an error
5253 : break;
5254 : }
5255 :
5256 2024 : lifetime_args.push_back (std::move (lifetime.value ()));
5257 :
5258 : // if next token isn't comma, then it must be end of list
5259 4048 : if (lexer.peek_token ()->get_id () != COMMA)
5260 : {
5261 : break;
5262 : }
5263 : // skip comma
5264 911 : lexer.skip_token ();
5265 :
5266 911 : t = lexer.peek_token ();
5267 : }
5268 :
5269 : // try to parse types and const generics second
5270 22593 : std::vector<AST::GenericArg> generic_args;
5271 :
5272 : // TODO: think of better control structure
5273 22593 : t = lexer.peek_token ();
5274 46285 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5275 : {
5276 : // FIXME: Is it fine to break if there is one binding? Can't there be
5277 : // bindings in between types?
5278 :
5279 : // ensure not binding being parsed as type accidently
5280 23692 : if (t->get_id () == IDENTIFIER
5281 47384 : && (lexer.peek_token (1)->get_id () == EQUAL
5282 41620 : || lexer.peek_token (1)->get_id () == COLON))
5283 : break;
5284 :
5285 23186 : auto arg = parse_generic_arg ();
5286 23186 : if (arg)
5287 : {
5288 23186 : generic_args.emplace_back (std::move (arg.value ()));
5289 : }
5290 :
5291 : // FIXME: Do we need to break if we encounter an error?
5292 :
5293 : // if next token isn't comma, then it must be end of list
5294 46372 : if (lexer.peek_token ()->get_id () != COMMA)
5295 : break;
5296 :
5297 : // skip comma
5298 2222 : lexer.skip_token ();
5299 2222 : t = lexer.peek_token ();
5300 : }
5301 :
5302 : // try to parse bindings third
5303 22593 : std::vector<AST::GenericArgsBinding> binding_args;
5304 :
5305 : // TODO: think of better control structure
5306 22593 : t = lexer.peek_token ();
5307 23109 : while (!Parse::Utils::is_right_angle_tok (t->get_id ()))
5308 : {
5309 516 : AST::GenericArgsBinding binding = parse_generic_args_binding ();
5310 516 : if (binding.is_error ())
5311 : {
5312 : // not necessarily an error
5313 : break;
5314 : }
5315 :
5316 516 : binding_args.push_back (std::move (binding));
5317 :
5318 : // if next token isn't comma, then it must be end of list
5319 1032 : if (lexer.peek_token ()->get_id () != COMMA)
5320 : {
5321 : break;
5322 : }
5323 : // skip comma
5324 10 : lexer.skip_token ();
5325 :
5326 10 : t = lexer.peek_token ();
5327 : }
5328 :
5329 : // skip any trailing commas
5330 45186 : if (lexer.peek_token ()->get_id () == COMMA)
5331 0 : lexer.skip_token ();
5332 :
5333 22593 : if (!skip_generics_right_angle ())
5334 0 : return AST::GenericArgs::create_empty ();
5335 :
5336 22593 : lifetime_args.shrink_to_fit ();
5337 22593 : generic_args.shrink_to_fit ();
5338 22593 : binding_args.shrink_to_fit ();
5339 :
5340 22593 : return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
5341 22593 : std::move (binding_args), locus);
5342 45186 : }
5343 :
5344 : // Parses a binding in a generic args path segment.
5345 : template <typename ManagedTokenSource>
5346 : AST::GenericArgsBinding
5347 516 : Parser<ManagedTokenSource>::parse_generic_args_binding ()
5348 : {
5349 516 : const_TokenPtr ident_tok = lexer.peek_token ();
5350 516 : if (ident_tok->get_id () != IDENTIFIER)
5351 : {
5352 : // allow non error-inducing use
5353 : // skip somewhere?
5354 0 : return AST::GenericArgsBinding::create_error ();
5355 : }
5356 516 : lexer.skip_token ();
5357 1032 : Identifier ident{ident_tok};
5358 :
5359 1032 : if (lexer.peek_token ()->get_id () == COLON)
5360 : {
5361 95 : lexer.skip_token ();
5362 95 : auto bounds_locus = lexer.peek_token ()->get_locus ();
5363 95 : auto bounds = parse_type_param_bounds ();
5364 95 : auto type = std::unique_ptr<AST::Type> (
5365 95 : new AST::ImplTraitType (std::move (bounds), bounds_locus));
5366 190 : return AST::GenericArgsBinding (
5367 : std::move (ident), std::move (type), ident_tok->get_locus (),
5368 190 : AST::GenericArgsBinding::Kind::Constraint);
5369 95 : }
5370 :
5371 421 : if (!skip_token (EQUAL))
5372 0 : return AST::GenericArgsBinding::create_error ();
5373 :
5374 : // parse type (required)
5375 421 : std::unique_ptr<AST::Type> type = parse_type ();
5376 421 : if (type == nullptr)
5377 : {
5378 : // skip somewhere?
5379 0 : return AST::GenericArgsBinding::create_error ();
5380 : }
5381 :
5382 842 : return AST::GenericArgsBinding (std::move (ident), std::move (type),
5383 842 : ident_tok->get_locus ());
5384 937 : }
5385 :
5386 : // Parses a self param. Also handles self param not existing.
5387 : template <typename ManagedTokenSource>
5388 : tl::expected<std::unique_ptr<AST::Param>, Parse::Error::Self>
5389 35822 : Parser<ManagedTokenSource>::parse_self_param ()
5390 : {
5391 35822 : bool has_reference = false;
5392 35822 : AST::Lifetime lifetime = AST::Lifetime::elided ();
5393 :
5394 35822 : location_t locus = lexer.peek_token ()->get_locus ();
5395 :
5396 : // TODO: Feels off, find a better way to clearly express this
5397 143288 : std::vector<std::vector<TokenId>> ptrs
5398 : = {{ASTERISK, SELF} /* *self */,
5399 : {ASTERISK, CONST, SELF} /* *const self */,
5400 : {ASTERISK, MUT, SELF} /* *mut self */};
5401 :
5402 143282 : for (auto &s : ptrs)
5403 : {
5404 : size_t i = 0;
5405 107474 : for (i = 0; i < s.size (); i++)
5406 214942 : if (lexer.peek_token (i)->get_id () != s[i])
5407 : break;
5408 107463 : if (i == s.size ())
5409 : {
5410 3 : Error error (lexer.peek_token ()->get_locus (),
5411 : "cannot pass %<self%> by raw pointer");
5412 3 : add_error (std::move (error));
5413 3 : return Parse::Error::Self::make_self_raw_pointer ();
5414 3 : }
5415 : }
5416 :
5417 : // Trying to find those patterns:
5418 : //
5419 : // &'lifetime mut self
5420 : // &'lifetime self
5421 : // & mut self
5422 : // & self
5423 : // mut self
5424 : // self
5425 : //
5426 : // If not found, it is probably a function, exit and let function parsing
5427 : // handle it.
5428 : bool is_self = false;
5429 214914 : for (size_t i = 0; i < 5; i++)
5430 358190 : if (lexer.peek_token (i)->get_id () == SELF)
5431 17826 : is_self = true;
5432 :
5433 35819 : if (!is_self)
5434 17998 : return Parse::Error::Self::make_not_self ();
5435 :
5436 : // test if self is a reference parameter
5437 35642 : if (lexer.peek_token ()->get_id () == AMP)
5438 : {
5439 9934 : has_reference = true;
5440 9934 : lexer.skip_token ();
5441 :
5442 : // now test whether it has a lifetime
5443 19868 : if (lexer.peek_token ()->get_id () == LIFETIME)
5444 : {
5445 : // something went wrong somehow
5446 106 : if (auto parsed_lifetime = parse_lifetime (true))
5447 : {
5448 53 : lifetime = parsed_lifetime.value ();
5449 : }
5450 : else
5451 : {
5452 0 : Error error (lexer.peek_token ()->get_locus (),
5453 : "failed to parse lifetime in self param");
5454 0 : add_error (std::move (error));
5455 :
5456 : // skip after somewhere?
5457 0 : return Parse::Error::Self::make_parsing_error ();
5458 0 : }
5459 : }
5460 : }
5461 :
5462 : // test for mut
5463 17821 : bool has_mut = false;
5464 35642 : if (lexer.peek_token ()->get_id () == MUT)
5465 : {
5466 2878 : has_mut = true;
5467 2878 : lexer.skip_token ();
5468 : }
5469 :
5470 : // skip self token
5471 17821 : const_TokenPtr self_tok = lexer.peek_token ();
5472 17821 : if (self_tok->get_id () != SELF)
5473 : {
5474 : // skip after somewhere?
5475 4 : return Parse::Error::Self::make_not_self ();
5476 : }
5477 17817 : lexer.skip_token ();
5478 :
5479 : // parse optional type
5480 17817 : std::unique_ptr<AST::Type> type = nullptr;
5481 35634 : if (lexer.peek_token ()->get_id () == COLON)
5482 : {
5483 28 : lexer.skip_token ();
5484 :
5485 : // type is now required
5486 28 : type = parse_type ();
5487 28 : if (type == nullptr)
5488 : {
5489 0 : Error error (lexer.peek_token ()->get_locus (),
5490 : "could not parse type in self param");
5491 0 : add_error (std::move (error));
5492 :
5493 : // skip after somewhere?
5494 0 : return Parse::Error::Self::make_parsing_error ();
5495 0 : }
5496 : }
5497 :
5498 : // ensure that cannot have both type and reference
5499 17817 : if (type && has_reference)
5500 : {
5501 0 : Error error (
5502 0 : lexer.peek_token ()->get_locus (),
5503 : "cannot have both a reference and a type specified in a self param");
5504 0 : add_error (std::move (error));
5505 :
5506 : // skip after somewhere?
5507 0 : return Parse::Error::Self::make_parsing_error ();
5508 0 : }
5509 :
5510 17817 : if (has_reference)
5511 : {
5512 9934 : return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
5513 9934 : locus);
5514 : }
5515 : else
5516 : {
5517 : // note that type may be nullptr here and that's fine
5518 7883 : return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
5519 7883 : locus);
5520 : }
5521 53639 : }
5522 :
5523 : /* Parses an expression or macro statement. */
5524 : template <typename ManagedTokenSource>
5525 : std::unique_ptr<AST::Stmt>
5526 643 : Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
5527 : ParseRestrictions restrictions)
5528 : {
5529 643 : location_t locus = lexer.peek_token ()->get_locus ();
5530 :
5531 643 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
5532 :
5533 1286 : switch (lexer.peek_token ()->get_id ())
5534 : {
5535 271 : case IDENTIFIER:
5536 : case CRATE:
5537 : case SUPER:
5538 : case SELF:
5539 : case SELF_ALIAS:
5540 : case DOLLAR_SIGN:
5541 : case SCOPE_RESOLUTION:
5542 : {
5543 271 : AST::PathInExpression path = parse_path_in_expression ();
5544 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
5545 271 : null_denotation;
5546 :
5547 542 : if (lexer.peek_token ()->get_id () == EXCLAM)
5548 : {
5549 61 : std::unique_ptr<AST::MacroInvocation> invoc
5550 122 : = parse_macro_invocation_partial (std::move (path),
5551 : std::move (outer_attrs));
5552 :
5553 61 : if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
5554 : {
5555 59 : invoc->add_semicolon ();
5556 : // Macro invocation with semicolon.
5557 59 : return invoc;
5558 : }
5559 :
5560 2 : TokenId after_macro = lexer.peek_token ()->get_id ();
5561 :
5562 2 : if (restrictions.allow_close_after_expr_stmt
5563 2 : && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
5564 : || after_macro == RIGHT_SQUARE))
5565 2 : return invoc;
5566 :
5567 0 : if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
5568 : == AST::CURLY
5569 0 : && after_macro != DOT && after_macro != QUESTION_MARK)
5570 : {
5571 0 : rust_debug ("braced macro statement");
5572 0 : return invoc;
5573 : }
5574 :
5575 0 : null_denotation = std::move (invoc);
5576 61 : }
5577 : else
5578 : {
5579 : null_denotation
5580 420 : = null_denotation_path (std::move (path), {}, restrictions);
5581 : }
5582 :
5583 840 : expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
5584 : std::move (outer_attrs), restrictions);
5585 : break;
5586 271 : }
5587 372 : default:
5588 372 : restrictions.expr_can_be_stmt = true;
5589 744 : expr = parse_expr (std::move (outer_attrs), restrictions);
5590 372 : break;
5591 : }
5592 :
5593 582 : if (!expr)
5594 : {
5595 : // expr is required, error
5596 0 : Error error (lexer.peek_token ()->get_locus (),
5597 : "failed to parse expr in expr statement");
5598 0 : add_error (std::move (error));
5599 :
5600 0 : skip_after_semicolon ();
5601 0 : return nullptr;
5602 0 : }
5603 :
5604 582 : bool has_semi = false;
5605 :
5606 582 : if (restrictions.consume_semi)
5607 : {
5608 566 : if (maybe_skip_token (SEMICOLON))
5609 : {
5610 166 : has_semi = true;
5611 : }
5612 400 : else if (expr.value ()->is_expr_without_block ())
5613 : {
5614 34 : if (restrictions.allow_close_after_expr_stmt)
5615 : {
5616 34 : TokenId id = lexer.peek_token ()->get_id ();
5617 34 : if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
5618 : {
5619 3 : expect_token (SEMICOLON);
5620 3 : return nullptr;
5621 : }
5622 : }
5623 : else
5624 : {
5625 0 : expect_token (SEMICOLON);
5626 0 : return nullptr;
5627 : }
5628 : }
5629 : }
5630 :
5631 579 : return std::make_unique<AST::ExprStmt> (std::move (expr.value ()), locus,
5632 579 : has_semi);
5633 643 : }
5634 :
5635 : // Parses a loop label used in loop expressions.
5636 : template <typename ManagedTokenSource>
5637 : tl::expected<AST::LoopLabel, Parse::Error::LoopLabel>
5638 61 : Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
5639 : {
5640 : // parse lifetime - if doesn't exist, assume no label
5641 61 : if (tok->get_id () != LIFETIME)
5642 : {
5643 : // not necessarily an error
5644 0 : return Parse::Error::LoopLabel::make_not_loop_label ();
5645 : }
5646 : /* FIXME: check for named lifetime requirement here? or check in semantic
5647 : * analysis phase? */
5648 122 : AST::Lifetime label = lifetime_from_token (tok);
5649 :
5650 61 : if (!skip_token (COLON))
5651 : {
5652 : // skip somewhere?
5653 61 : Parse::Error::LoopLabel::make_missing_colon ();
5654 : }
5655 :
5656 : return tl::expected<AST::LoopLabel, Parse::Error::LoopLabel> (
5657 61 : AST::LoopLabel (std::move (label), tok->get_locus ()));
5658 61 : }
5659 :
5660 : // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
5661 : template <typename ManagedTokenSource>
5662 : AST::MatchArm
5663 50502 : Parser<ManagedTokenSource>::parse_match_arm ()
5664 : {
5665 : // parse optional outer attributes
5666 50502 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5667 :
5668 : // DEBUG
5669 50502 : rust_debug ("about to start parsing match arm patterns");
5670 :
5671 : // break early if find right curly
5672 101004 : if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
5673 : {
5674 : // not an error
5675 0 : return AST::MatchArm::create_error ();
5676 : }
5677 :
5678 : // parse match arm patterns - at least 1 is required
5679 50502 : std::unique_ptr<AST::Pattern> match_arm_pattern
5680 : = parse_match_arm_pattern (RIGHT_CURLY);
5681 50502 : if (match_arm_pattern == nullptr)
5682 : {
5683 0 : Error error (lexer.peek_token ()->get_locus (),
5684 : "failed to parse any patterns in match arm");
5685 0 : add_error (std::move (error));
5686 :
5687 : // skip somewhere?
5688 0 : return AST::MatchArm::create_error ();
5689 0 : }
5690 :
5691 : // DEBUG
5692 50502 : rust_debug ("successfully parsed match arm patterns");
5693 :
5694 : // parse match arm guard expr if it exists
5695 50502 : std::unique_ptr<AST::Expr> guard_expr = nullptr;
5696 101004 : if (lexer.peek_token ()->get_id () == IF)
5697 : {
5698 104 : lexer.skip_token ();
5699 :
5700 104 : auto guard_expr_res = parse_expr ();
5701 104 : if (!guard_expr_res)
5702 : {
5703 0 : Error error (lexer.peek_token ()->get_locus (),
5704 : "failed to parse guard expression in match arm");
5705 0 : add_error (std::move (error));
5706 :
5707 : // skip somewhere?
5708 0 : return AST::MatchArm::create_error ();
5709 0 : }
5710 104 : guard_expr = std::move (guard_expr_res.value ());
5711 104 : }
5712 :
5713 : // DEBUG
5714 50502 : rust_debug ("successfully parsed match arm");
5715 :
5716 101004 : return AST::MatchArm (std::move (match_arm_pattern),
5717 101004 : lexer.peek_token ()->get_locus (),
5718 50502 : std::move (guard_expr), std::move (outer_attrs));
5719 50502 : }
5720 :
5721 : /* Parses the patterns used in a match arm. End token id is the id of the
5722 : * token that would exist after the patterns are done (e.g. '}' for match
5723 : * expr, '=' for if let and while let). */
5724 : template <typename ManagedTokenSource>
5725 : std::unique_ptr<AST::Pattern>
5726 50717 : Parser<ManagedTokenSource>::parse_match_arm_pattern (TokenId end_token_id)
5727 : {
5728 : // skip optional leading '|'
5729 101434 : if (lexer.peek_token ()->get_id () == PIPE)
5730 0 : lexer.skip_token ();
5731 : /* TODO: do I even need to store the result of this? can't be used.
5732 : * If semantically different, I need a wrapped "match arm patterns" object
5733 : * for this. */
5734 :
5735 50717 : std::unique_ptr<AST::Pattern> pattern;
5736 :
5737 : // quick break out if end_token_id
5738 101434 : if (lexer.peek_token ()->get_id () == end_token_id)
5739 1 : return pattern;
5740 :
5741 : // parse required pattern - if doesn't exist, return empty
5742 50716 : std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
5743 50716 : if (initial_pattern == nullptr)
5744 : {
5745 : // FIXME: should this be an error?
5746 0 : return pattern;
5747 : }
5748 :
5749 50716 : return initial_pattern;
5750 50717 : }
5751 :
5752 : // Parses a single parameter used in a closure definition.
5753 : template <typename ManagedTokenSource>
5754 : AST::ClosureParam
5755 611 : Parser<ManagedTokenSource>::parse_closure_param ()
5756 : {
5757 611 : AST::AttrVec outer_attrs = parse_outer_attributes ();
5758 :
5759 : // parse pattern (which is required)
5760 611 : std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
5761 611 : if (pattern == nullptr)
5762 : {
5763 : // not necessarily an error
5764 0 : return AST::ClosureParam::create_error ();
5765 : }
5766 :
5767 : // parse optional type of param
5768 611 : std::unique_ptr<AST::Type> type = nullptr;
5769 1222 : if (lexer.peek_token ()->get_id () == COLON)
5770 : {
5771 88 : lexer.skip_token ();
5772 :
5773 : // parse type, which is now required
5774 88 : type = parse_type ();
5775 88 : if (type == nullptr)
5776 : {
5777 0 : Error error (lexer.peek_token ()->get_locus (),
5778 : "failed to parse type in closure parameter");
5779 0 : add_error (std::move (error));
5780 :
5781 : // skip somewhere?
5782 0 : return AST::ClosureParam::create_error ();
5783 0 : }
5784 : }
5785 :
5786 611 : location_t loc = pattern->get_locus ();
5787 611 : return AST::ClosureParam (std::move (pattern), loc, std::move (type),
5788 611 : std::move (outer_attrs));
5789 611 : }
5790 :
5791 : // Parses a type (will further disambiguate any type).
5792 : template <typename ManagedTokenSource>
5793 : std::unique_ptr<AST::Type>
5794 118134 : Parser<ManagedTokenSource>::parse_type (bool save_errors)
5795 : {
5796 : /* rules for all types:
5797 : * NeverType: '!'
5798 : * SliceType: '[' Type ']'
5799 : * InferredType: '_'
5800 : * MacroInvocation: SimplePath '!' DelimTokenTree
5801 : * ParenthesisedType: '(' Type ')'
5802 : * ImplTraitType: 'impl' TypeParamBounds
5803 : * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'?
5804 : * TypeParamBound Lifetime | TraitBound
5805 : * ImplTraitTypeOneBound: 'impl' TraitBound
5806 : * TraitObjectType: 'dyn'? TypeParamBounds
5807 : * TraitObjectTypeOneBound: 'dyn'? TraitBound
5808 : * TraitBound '?'? ForLifetimes? TypePath | '(' '?'?
5809 : * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes?
5810 : * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
5811 : * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )?
5812 : * 'unsafe'?
5813 : * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>'
5814 : * (
5815 : * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment (
5816 : * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']'
5817 : * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds
5818 : * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds
5819 : * TupleType: '(' Type etc. - regular tuple stuff. Also
5820 : * regular tuple vs parenthesised precedence
5821 : *
5822 : * Disambiguate between macro and type path via type path being parsed, and
5823 : * then if '!' found, convert type path to simple path for macro. Usual
5824 : * disambiguation for tuple vs parenthesised. For ImplTraitType and
5825 : * TraitObjectType individual disambiguations, they seem more like "special
5826 : * cases", so probably just try to parse the more general ImplTraitType or
5827 : * TraitObjectType and return OneBound versions if they satisfy those
5828 : * criteria. */
5829 :
5830 118134 : const_TokenPtr t = lexer.peek_token ();
5831 118134 : switch (t->get_id ())
5832 : {
5833 258 : case EXCLAM:
5834 : // never type - can't be macro as no path beforehand
5835 258 : lexer.skip_token ();
5836 258 : return std::unique_ptr<AST::NeverType> (
5837 258 : new AST::NeverType (t->get_locus ()));
5838 1530 : case LEFT_SQUARE:
5839 : // slice type or array type - requires further disambiguation
5840 1530 : return parse_slice_or_array_type ();
5841 3557 : case LEFT_SHIFT:
5842 : case LEFT_ANGLE:
5843 : {
5844 : // qualified path in type
5845 3557 : AST::QualifiedPathInType path = parse_qualified_path_in_type ();
5846 3557 : if (path.is_error ())
5847 : {
5848 0 : if (save_errors)
5849 : {
5850 0 : Error error (t->get_locus (),
5851 : "failed to parse qualified path in type");
5852 0 : add_error (std::move (error));
5853 0 : }
5854 :
5855 0 : return nullptr;
5856 : }
5857 3557 : return std::unique_ptr<AST::QualifiedPathInType> (
5858 3557 : new AST::QualifiedPathInType (std::move (path)));
5859 3557 : }
5860 337 : case UNDERSCORE:
5861 : // inferred type
5862 337 : lexer.skip_token ();
5863 337 : return std::unique_ptr<AST::InferredType> (
5864 337 : new AST::InferredType (t->get_locus ()));
5865 3890 : case ASTERISK:
5866 : // raw pointer type
5867 3890 : return parse_raw_pointer_type ();
5868 12978 : case AMP: // does this also include AMP_AMP?
5869 : case LOGICAL_AND:
5870 : // reference type
5871 12978 : return parse_reference_type ();
5872 0 : case LIFETIME:
5873 : {
5874 : /* probably a lifetime bound, so probably type param bounds in
5875 : * TraitObjectType */
5876 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
5877 : = parse_type_param_bounds ();
5878 :
5879 0 : return std::unique_ptr<AST::TraitObjectType> (
5880 0 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
5881 0 : false));
5882 0 : }
5883 93212 : case IDENTIFIER:
5884 : case SUPER:
5885 : case SELF:
5886 : case SELF_ALIAS:
5887 : case CRATE:
5888 : case DOLLAR_SIGN:
5889 : case SCOPE_RESOLUTION:
5890 : {
5891 : // macro invocation or type path - requires further disambiguation.
5892 : /* for parsing path component of each rule, perhaps parse it as a
5893 : * typepath and attempt conversion to simplepath if a trailing '!' is
5894 : * found */
5895 : /* Type path also includes TraitObjectTypeOneBound BUT if it starts
5896 : * with it, it is exactly the same as a TypePath syntactically, so
5897 : * this is a syntactical ambiguity. As such, the parser will parse it
5898 : * as a TypePath. This, however, does not prevent TraitObjectType from
5899 : * starting with a typepath. */
5900 :
5901 : // parse path as type path
5902 93212 : AST::TypePath path = parse_type_path ();
5903 93212 : if (path.is_error ())
5904 : {
5905 0 : if (save_errors)
5906 : {
5907 0 : Error error (t->get_locus (),
5908 : "failed to parse path as first component of type");
5909 0 : add_error (std::move (error));
5910 0 : }
5911 :
5912 0 : return nullptr;
5913 : }
5914 93212 : location_t locus = path.get_locus ();
5915 :
5916 : // branch on next token
5917 93212 : t = lexer.peek_token ();
5918 93212 : switch (t->get_id ())
5919 : {
5920 497 : case EXCLAM:
5921 : {
5922 : // macro invocation
5923 : // convert to simple path
5924 497 : AST::SimplePath macro_path = path.as_simple_path ();
5925 497 : if (macro_path.is_empty ())
5926 : {
5927 0 : if (save_errors)
5928 : {
5929 0 : Error error (t->get_locus (),
5930 : "failed to parse simple path in macro "
5931 : "invocation (for type)");
5932 0 : add_error (std::move (error));
5933 0 : }
5934 :
5935 0 : return nullptr;
5936 : }
5937 :
5938 497 : lexer.skip_token ();
5939 :
5940 497 : auto tok_tree = parse_delim_token_tree ();
5941 497 : if (!tok_tree)
5942 0 : return nullptr;
5943 :
5944 994 : return AST::MacroInvocation::Regular (
5945 994 : AST::MacroInvocData (std::move (macro_path),
5946 497 : std::move (tok_tree.value ())),
5947 497 : {}, locus);
5948 994 : }
5949 29 : case PLUS:
5950 : {
5951 : // type param bounds
5952 29 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5953 :
5954 : // convert type path to trait bound
5955 29 : std::unique_ptr<AST::TraitBound> path_bound (
5956 29 : new AST::TraitBound (std::move (path), locus, false, false));
5957 29 : bounds.push_back (std::move (path_bound));
5958 :
5959 : /* parse rest of bounds - FIXME: better way to find when to stop
5960 : * parsing */
5961 58 : while (t->get_id () == PLUS)
5962 : {
5963 29 : lexer.skip_token ();
5964 :
5965 : // parse bound if it exists - if not, assume end of sequence
5966 29 : std::unique_ptr<AST::TypeParamBound> bound
5967 : = parse_type_param_bound ();
5968 29 : if (bound == nullptr)
5969 : {
5970 : break;
5971 : }
5972 29 : bounds.push_back (std::move (bound));
5973 :
5974 29 : t = lexer.peek_token ();
5975 : }
5976 :
5977 29 : return std::unique_ptr<AST::TraitObjectType> (
5978 29 : new AST::TraitObjectType (std::move (bounds), locus, false));
5979 29 : }
5980 92686 : default:
5981 : // assume that this is a type path and not an error
5982 92686 : return std::unique_ptr<AST::TypePath> (
5983 92686 : new AST::TypePath (std::move (path)));
5984 : }
5985 93212 : }
5986 1353 : case LEFT_PAREN:
5987 : /* tuple type or parenthesised type - requires further disambiguation
5988 : * (the usual). ok apparently can be a parenthesised TraitBound too, so
5989 : * could be TraitObjectTypeOneBound or TraitObjectType */
5990 1353 : return parse_paren_prefixed_type ();
5991 5 : case FOR:
5992 : // TraitObjectTypeOneBound or BareFunctionType
5993 5 : return parse_for_prefixed_type ();
5994 695 : case ASYNC:
5995 : case CONST:
5996 : case UNSAFE:
5997 : case EXTERN_KW:
5998 : case FN_KW:
5999 : // bare function type (with no for lifetimes)
6000 695 : return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
6001 243 : case IMPL:
6002 243 : lexer.skip_token ();
6003 486 : if (lexer.peek_token ()->get_id () == LIFETIME)
6004 : {
6005 : /* cannot be one bound because lifetime prevents it from being
6006 : * traitbound */
6007 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
6008 : = parse_type_param_bounds ();
6009 :
6010 0 : return std::unique_ptr<AST::ImplTraitType> (
6011 0 : new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
6012 0 : }
6013 : else
6014 : {
6015 : // should be trait bound, so parse trait bound
6016 243 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
6017 243 : if (initial_bound == nullptr)
6018 : {
6019 0 : if (save_errors)
6020 : {
6021 0 : Error error (lexer.peek_token ()->get_locus (),
6022 : "failed to parse ImplTraitType initial bound");
6023 0 : add_error (std::move (error));
6024 0 : }
6025 :
6026 0 : return nullptr;
6027 : }
6028 :
6029 243 : location_t locus = t->get_locus ();
6030 :
6031 : // short cut if next token isn't '+'
6032 243 : t = lexer.peek_token ();
6033 243 : if (t->get_id () != PLUS)
6034 : {
6035 239 : return std::unique_ptr<AST::ImplTraitTypeOneBound> (
6036 239 : new AST::ImplTraitTypeOneBound (std::move (initial_bound),
6037 239 : locus));
6038 : }
6039 :
6040 : // parse additional type param bounds
6041 4 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6042 4 : bounds.push_back (std::move (initial_bound));
6043 8 : while (t->get_id () == PLUS)
6044 : {
6045 4 : lexer.skip_token ();
6046 :
6047 : // parse bound if it exists
6048 4 : std::unique_ptr<AST::TypeParamBound> bound
6049 : = parse_type_param_bound ();
6050 4 : if (bound == nullptr)
6051 : {
6052 : // not an error as trailing plus may exist
6053 : break;
6054 : }
6055 4 : bounds.push_back (std::move (bound));
6056 :
6057 4 : t = lexer.peek_token ();
6058 : }
6059 :
6060 4 : return std::unique_ptr<AST::ImplTraitType> (
6061 4 : new AST::ImplTraitType (std::move (bounds), locus));
6062 243 : }
6063 60 : case DYN:
6064 : case QUESTION_MARK:
6065 : {
6066 : // either TraitObjectType or TraitObjectTypeOneBound
6067 60 : bool has_dyn = false;
6068 60 : if (t->get_id () == DYN)
6069 : {
6070 60 : lexer.skip_token ();
6071 60 : has_dyn = true;
6072 : }
6073 :
6074 120 : if (lexer.peek_token ()->get_id () == LIFETIME)
6075 : {
6076 : /* cannot be one bound because lifetime prevents it from being
6077 : * traitbound */
6078 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
6079 : = parse_type_param_bounds ();
6080 :
6081 0 : return std::unique_ptr<AST::TraitObjectType> (
6082 0 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
6083 0 : has_dyn));
6084 0 : }
6085 : else
6086 : {
6087 : // should be trait bound, so parse trait bound
6088 60 : std::unique_ptr<AST::TraitBound> initial_bound
6089 : = parse_trait_bound ();
6090 60 : if (initial_bound == nullptr)
6091 : {
6092 2 : if (save_errors)
6093 : {
6094 2 : Error error (
6095 2 : lexer.peek_token ()->get_locus (),
6096 : "failed to parse TraitObjectType initial bound");
6097 2 : add_error (std::move (error));
6098 2 : }
6099 :
6100 2 : return nullptr;
6101 : }
6102 :
6103 : // short cut if next token isn't '+'
6104 58 : t = lexer.peek_token ();
6105 58 : if (t->get_id () != PLUS)
6106 : {
6107 : // convert trait bound to value object
6108 27 : AST::TraitBound value_bound (*initial_bound);
6109 :
6110 : // DEBUG: removed as unique ptr, so should auto delete
6111 : // delete initial_bound;
6112 :
6113 27 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6114 54 : new AST::TraitObjectTypeOneBound (std::move (value_bound),
6115 27 : t->get_locus (), has_dyn));
6116 27 : }
6117 :
6118 : // parse additional type param bounds
6119 31 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6120 31 : bounds.push_back (std::move (initial_bound));
6121 72 : while (t->get_id () == PLUS)
6122 : {
6123 41 : lexer.skip_token ();
6124 :
6125 : // parse bound if it exists
6126 41 : std::unique_ptr<AST::TypeParamBound> bound
6127 : = parse_type_param_bound ();
6128 41 : if (bound == nullptr)
6129 : {
6130 : // not an error as trailing plus may exist
6131 : break;
6132 : }
6133 41 : bounds.push_back (std::move (bound));
6134 :
6135 41 : t = lexer.peek_token ();
6136 : }
6137 :
6138 31 : return std::unique_ptr<AST::TraitObjectType> (
6139 31 : new AST::TraitObjectType (std::move (bounds), t->get_locus (),
6140 31 : has_dyn));
6141 60 : }
6142 : }
6143 16 : default:
6144 16 : if (save_errors)
6145 16 : add_error (Error (t->get_locus (), "unrecognised token %qs in type",
6146 : t->get_token_description ()));
6147 :
6148 16 : return nullptr;
6149 : }
6150 118134 : }
6151 :
6152 : /* Parses a type that has '(' as its first character. Returns a tuple type,
6153 : * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
6154 : * on following characters. */
6155 : template <typename ManagedTokenSource>
6156 : std::unique_ptr<AST::Type>
6157 1353 : Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
6158 : {
6159 : /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
6160 : * a trait bound, not a parenthesised type, so that it can still be used in
6161 : * type param bounds. */
6162 :
6163 : /* NOTE: this implementation is really shit but I couldn't think of a better
6164 : * one. It requires essentially breaking polymorphism and downcasting via
6165 : * virtual method abuse, as it was copied from the rustc implementation (in
6166 : * which types are reified due to tagged union), after a more OOP attempt by
6167 : * me failed. */
6168 1353 : location_t left_delim_locus = lexer.peek_token ()->get_locus ();
6169 :
6170 : // skip left delim
6171 1353 : lexer.skip_token ();
6172 : /* while next token isn't close delim, parse comma-separated types, saving
6173 : * whether trailing comma happens */
6174 1353 : const_TokenPtr t = lexer.peek_token ();
6175 1353 : bool trailing_comma = true;
6176 1353 : std::vector<std::unique_ptr<AST::Type>> types;
6177 :
6178 3071 : while (t->get_id () != RIGHT_PAREN)
6179 : {
6180 2677 : std::unique_ptr<AST::Type> type = parse_type ();
6181 2677 : if (type == nullptr)
6182 : {
6183 0 : Error error (t->get_locus (),
6184 : "failed to parse type inside parentheses (probably "
6185 : "tuple or parenthesised)");
6186 0 : add_error (std::move (error));
6187 :
6188 0 : return nullptr;
6189 0 : }
6190 2677 : types.push_back (std::move (type));
6191 :
6192 2677 : t = lexer.peek_token ();
6193 2677 : if (t->get_id () != COMMA)
6194 : {
6195 959 : trailing_comma = false;
6196 : break;
6197 : }
6198 1718 : lexer.skip_token ();
6199 :
6200 1718 : t = lexer.peek_token ();
6201 : }
6202 :
6203 1353 : if (!skip_token (RIGHT_PAREN))
6204 : {
6205 0 : return nullptr;
6206 : }
6207 :
6208 : // if only one type and no trailing comma, then not a tuple type
6209 1353 : if (types.size () == 1 && !trailing_comma)
6210 : {
6211 : // must be a TraitObjectType (with more than one bound)
6212 10 : if (lexer.peek_token ()->get_id () == PLUS)
6213 : {
6214 : // create type param bounds vector
6215 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6216 :
6217 : // HACK: convert type to traitbound and add to bounds
6218 0 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6219 0 : std::unique_ptr<AST::TraitBound> converted_bound (
6220 0 : released_ptr->to_trait_bound (true));
6221 0 : if (converted_bound == nullptr)
6222 : {
6223 0 : Error error (
6224 0 : lexer.peek_token ()->get_locus (),
6225 : "failed to hackily converted parsed type to trait bound");
6226 0 : add_error (std::move (error));
6227 :
6228 0 : return nullptr;
6229 0 : }
6230 0 : bounds.push_back (std::move (converted_bound));
6231 :
6232 0 : t = lexer.peek_token ();
6233 0 : while (t->get_id () == PLUS)
6234 : {
6235 0 : lexer.skip_token ();
6236 :
6237 : // attempt to parse typeparambound
6238 0 : std::unique_ptr<AST::TypeParamBound> bound
6239 : = parse_type_param_bound ();
6240 0 : if (bound == nullptr)
6241 : {
6242 : // not an error if null
6243 : break;
6244 : }
6245 0 : bounds.push_back (std::move (bound));
6246 :
6247 0 : t = lexer.peek_token ();
6248 : }
6249 :
6250 0 : return std::unique_ptr<AST::TraitObjectType> (
6251 0 : new AST::TraitObjectType (std::move (bounds), left_delim_locus,
6252 0 : false));
6253 0 : }
6254 : else
6255 : {
6256 : // release vector pointer
6257 5 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
6258 : /* HACK: attempt to convert to trait bound. if fails, parenthesised
6259 : * type */
6260 5 : std::unique_ptr<AST::TraitBound> converted_bound (
6261 5 : released_ptr->to_trait_bound (true));
6262 5 : if (converted_bound == nullptr)
6263 : {
6264 : // parenthesised type
6265 5 : return std::unique_ptr<AST::ParenthesisedType> (
6266 5 : new AST::ParenthesisedType (std::move (released_ptr),
6267 5 : left_delim_locus));
6268 : }
6269 : else
6270 : {
6271 : // trait object type (one bound)
6272 :
6273 : // get value semantics trait bound
6274 0 : AST::TraitBound value_bound (*converted_bound);
6275 :
6276 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6277 0 : new AST::TraitObjectTypeOneBound (value_bound,
6278 0 : left_delim_locus));
6279 0 : }
6280 5 : }
6281 : }
6282 : else
6283 : {
6284 1348 : return std::unique_ptr<AST::TupleType> (
6285 1348 : new AST::TupleType (std::move (types), left_delim_locus));
6286 : }
6287 : /* TODO: ensure that this ensures that dynamic dispatch for traits is not
6288 : * lost somehow */
6289 1353 : }
6290 :
6291 : /* Parses a type that has 'for' as its first character. This means it has a
6292 : * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
6293 : * TraitObjectTypeOneBound depending on following characters. */
6294 : template <typename ManagedTokenSource>
6295 : std::unique_ptr<AST::Type>
6296 5 : Parser<ManagedTokenSource>::parse_for_prefixed_type ()
6297 : {
6298 5 : location_t for_locus = lexer.peek_token ()->get_locus ();
6299 : // parse for lifetimes in type
6300 5 : std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
6301 :
6302 : // branch on next token - either function or a trait type
6303 5 : const_TokenPtr t = lexer.peek_token ();
6304 5 : switch (t->get_id ())
6305 : {
6306 4 : case ASYNC:
6307 : case CONST:
6308 : case UNSAFE:
6309 : case EXTERN_KW:
6310 : case FN_KW:
6311 4 : return parse_bare_function_type (std::move (for_lifetimes));
6312 1 : case SCOPE_RESOLUTION:
6313 : case IDENTIFIER:
6314 : case SUPER:
6315 : case SELF:
6316 : case SELF_ALIAS:
6317 : case CRATE:
6318 : case DOLLAR_SIGN:
6319 : {
6320 : // path, so trait type
6321 :
6322 : // parse type path to finish parsing trait bound
6323 1 : AST::TypePath path = parse_type_path ();
6324 :
6325 1 : t = lexer.peek_token ();
6326 1 : if (t->get_id () != PLUS)
6327 : {
6328 : // must be one-bound trait type
6329 : // create trait bound value object
6330 1 : AST::TraitBound bound (std::move (path), for_locus, false, false,
6331 : std::move (for_lifetimes));
6332 :
6333 1 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6334 2 : new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
6335 1 : }
6336 :
6337 : /* more than one bound trait type (or at least parsed as it - could be
6338 : * trailing '+') create trait bound pointer and bounds */
6339 0 : std::unique_ptr<AST::TraitBound> initial_bound (
6340 0 : new AST::TraitBound (std::move (path), for_locus, false, false,
6341 : std::move (for_lifetimes)));
6342 0 : std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
6343 0 : bounds.push_back (std::move (initial_bound));
6344 :
6345 0 : while (t->get_id () == PLUS)
6346 : {
6347 0 : lexer.skip_token ();
6348 :
6349 : // parse type param bound if it exists
6350 0 : std::unique_ptr<AST::TypeParamBound> bound
6351 : = parse_type_param_bound ();
6352 0 : if (bound == nullptr)
6353 : {
6354 : // not an error - e.g. trailing plus
6355 0 : return nullptr;
6356 : }
6357 0 : bounds.push_back (std::move (bound));
6358 :
6359 0 : t = lexer.peek_token ();
6360 : }
6361 :
6362 0 : return std::unique_ptr<AST::TraitObjectType> (
6363 0 : new AST::TraitObjectType (std::move (bounds), for_locus, false));
6364 1 : }
6365 0 : default:
6366 : // error
6367 0 : add_error (Error (t->get_locus (),
6368 : "unrecognised token %qs in bare function type or trait "
6369 : "object type or trait object type one bound",
6370 : t->get_token_description ()));
6371 :
6372 0 : return nullptr;
6373 : }
6374 5 : }
6375 :
6376 : // Parses a maybe named param used in bare function types.
6377 : template <typename ManagedTokenSource>
6378 : AST::MaybeNamedParam
6379 3824 : Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
6380 : {
6381 : /* Basically guess that param is named if first token is identifier or
6382 : * underscore and second token is semicolon. This should probably have no
6383 : * exceptions. rustc uses backtracking to parse these, but at the time of
6384 : * writing gccrs has no backtracking capabilities. */
6385 3824 : const_TokenPtr current = lexer.peek_token ();
6386 3824 : const_TokenPtr next = lexer.peek_token (1);
6387 :
6388 3824 : Identifier name;
6389 3824 : AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
6390 :
6391 3824 : if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
6392 : {
6393 : // named param
6394 1 : name = {current};
6395 1 : kind = AST::MaybeNamedParam::IDENTIFIER;
6396 1 : lexer.skip_token (1);
6397 : }
6398 3823 : else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
6399 : {
6400 : // wildcard param
6401 12 : name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
6402 6 : kind = AST::MaybeNamedParam::WILDCARD;
6403 6 : lexer.skip_token (1);
6404 : }
6405 :
6406 : // parse type (required)
6407 3824 : std::unique_ptr<AST::Type> type = parse_type ();
6408 3824 : if (type == nullptr)
6409 : {
6410 0 : Error error (lexer.peek_token ()->get_locus (),
6411 : "failed to parse type in maybe named param");
6412 0 : add_error (std::move (error));
6413 :
6414 0 : return AST::MaybeNamedParam::create_error ();
6415 0 : }
6416 :
6417 7648 : return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
6418 3824 : std::move (outer_attrs), current->get_locus ());
6419 7648 : }
6420 :
6421 : /* Parses a bare function type (with the given for lifetimes for convenience -
6422 : * does not parse them itself). */
6423 : template <typename ManagedTokenSource>
6424 : std::unique_ptr<AST::BareFunctionType>
6425 701 : Parser<ManagedTokenSource>::parse_bare_function_type (
6426 : std::vector<AST::LifetimeParam> for_lifetimes)
6427 : {
6428 : // TODO: pass in for lifetime location as param
6429 701 : location_t best_try_locus = lexer.peek_token ()->get_locus ();
6430 :
6431 701 : auto qualifiers = parse_function_qualifiers ();
6432 701 : if (!qualifiers)
6433 0 : return nullptr;
6434 :
6435 701 : if (!skip_token (FN_KW))
6436 0 : return nullptr;
6437 :
6438 701 : if (!skip_token (LEFT_PAREN))
6439 0 : return nullptr;
6440 :
6441 : // parse function params, if they exist
6442 701 : std::vector<AST::MaybeNamedParam> params;
6443 701 : bool is_variadic = false;
6444 701 : AST::AttrVec variadic_attrs;
6445 :
6446 701 : const_TokenPtr t = lexer.peek_token ();
6447 8089 : while (t->get_id () != RIGHT_PAREN)
6448 : {
6449 4016 : AST::AttrVec temp_attrs = parse_outer_attributes ();
6450 :
6451 8032 : if (lexer.peek_token ()->get_id () == ELLIPSIS)
6452 : {
6453 192 : lexer.skip_token ();
6454 192 : is_variadic = true;
6455 192 : variadic_attrs = std::move (temp_attrs);
6456 :
6457 192 : t = lexer.peek_token ();
6458 :
6459 192 : if (t->get_id () != RIGHT_PAREN)
6460 : {
6461 0 : Error error (t->get_locus (),
6462 : "expected right parentheses after variadic in maybe "
6463 : "named function "
6464 : "parameters, found %qs",
6465 : t->get_token_description ());
6466 0 : add_error (std::move (error));
6467 :
6468 0 : return nullptr;
6469 0 : }
6470 :
6471 : break;
6472 : }
6473 :
6474 3824 : AST::MaybeNamedParam param
6475 3824 : = parse_maybe_named_param (std::move (temp_attrs));
6476 3824 : if (param.is_error ())
6477 : {
6478 0 : Error error (
6479 0 : lexer.peek_token ()->get_locus (),
6480 : "failed to parse maybe named param in bare function type");
6481 0 : add_error (std::move (error));
6482 :
6483 0 : return nullptr;
6484 0 : }
6485 3824 : params.push_back (std::move (param));
6486 :
6487 7648 : if (lexer.peek_token ()->get_id () != COMMA)
6488 : break;
6489 :
6490 3372 : lexer.skip_token ();
6491 3372 : t = lexer.peek_token ();
6492 : }
6493 :
6494 701 : if (!skip_token (RIGHT_PAREN))
6495 0 : return nullptr;
6496 :
6497 : // bare function return type, if exists
6498 701 : std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
6499 1402 : if (lexer.peek_token ()->get_id () == RETURN_TYPE)
6500 : {
6501 672 : lexer.skip_token ();
6502 :
6503 : // parse required TypeNoBounds
6504 672 : return_type = parse_type_no_bounds ();
6505 672 : if (return_type == nullptr)
6506 : {
6507 0 : Error error (lexer.peek_token ()->get_locus (),
6508 : "failed to parse return type (type no bounds) in bare "
6509 : "function type");
6510 0 : add_error (std::move (error));
6511 :
6512 0 : return nullptr;
6513 0 : }
6514 : }
6515 :
6516 701 : return std::unique_ptr<AST::BareFunctionType> (new AST::BareFunctionType (
6517 701 : std::move (for_lifetimes), std::move (qualifiers.value ()),
6518 : std::move (params), is_variadic, std::move (variadic_attrs),
6519 701 : std::move (return_type), best_try_locus));
6520 1402 : }
6521 :
6522 : template <typename ManagedTokenSource>
6523 : std::unique_ptr<AST::ReferenceType>
6524 13054 : Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
6525 : {
6526 : // parse optional lifetime
6527 13054 : AST::Lifetime lifetime = AST::Lifetime::elided ();
6528 26108 : if (lexer.peek_token ()->get_id () == LIFETIME)
6529 : {
6530 2120 : auto parsed_lifetime = parse_lifetime (true);
6531 2120 : if (parsed_lifetime)
6532 : {
6533 2120 : lifetime = parsed_lifetime.value ();
6534 : }
6535 : else
6536 : {
6537 0 : Error error (lexer.peek_token ()->get_locus (),
6538 : "failed to parse lifetime in reference type");
6539 0 : add_error (std::move (error));
6540 :
6541 0 : return nullptr;
6542 0 : }
6543 2120 : }
6544 :
6545 13054 : bool is_mut = false;
6546 26108 : if (lexer.peek_token ()->get_id () == MUT)
6547 : {
6548 1961 : lexer.skip_token ();
6549 1961 : is_mut = true;
6550 : }
6551 :
6552 : // parse type no bounds, which is required
6553 13054 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
6554 13054 : if (type == nullptr)
6555 : {
6556 0 : Error error (lexer.peek_token ()->get_locus (),
6557 : "failed to parse referenced type in reference type");
6558 0 : add_error (std::move (error));
6559 :
6560 0 : return nullptr;
6561 0 : }
6562 :
6563 : return std::unique_ptr<AST::ReferenceType> (
6564 39162 : new AST::ReferenceType (is_mut, std::move (type), locus,
6565 13054 : std::move (lifetime)));
6566 13054 : }
6567 :
6568 : // Parses a reference type (mutable or immutable, with given lifetime).
6569 : template <typename ManagedTokenSource>
6570 : std::unique_ptr<AST::ReferenceType>
6571 13054 : Parser<ManagedTokenSource>::parse_reference_type ()
6572 : {
6573 13054 : auto t = lexer.peek_token ();
6574 13054 : auto locus = t->get_locus ();
6575 :
6576 13054 : switch (t->get_id ())
6577 : {
6578 13006 : case AMP:
6579 13006 : skip_token (AMP);
6580 13006 : return parse_reference_type_inner (locus);
6581 48 : case LOGICAL_AND:
6582 48 : skip_token (LOGICAL_AND);
6583 : return std::unique_ptr<AST::ReferenceType> (
6584 144 : new AST::ReferenceType (false, parse_reference_type_inner (locus),
6585 48 : locus));
6586 0 : default:
6587 0 : rust_unreachable ();
6588 : }
6589 13054 : }
6590 :
6591 : // Parses a raw (unsafe) pointer type.
6592 : template <typename ManagedTokenSource>
6593 : std::unique_ptr<AST::RawPointerType>
6594 8784 : Parser<ManagedTokenSource>::parse_raw_pointer_type ()
6595 : {
6596 8784 : location_t locus = lexer.peek_token ()->get_locus ();
6597 8784 : skip_token (ASTERISK);
6598 :
6599 8784 : AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
6600 :
6601 : // branch on next token for pointer kind info
6602 8784 : const_TokenPtr t = lexer.peek_token ();
6603 8784 : switch (t->get_id ())
6604 : {
6605 1718 : case MUT:
6606 1718 : kind = AST::RawPointerType::MUT;
6607 1718 : lexer.skip_token ();
6608 1718 : break;
6609 7066 : case CONST:
6610 7066 : kind = AST::RawPointerType::CONST;
6611 7066 : lexer.skip_token ();
6612 7066 : break;
6613 0 : default:
6614 0 : add_error (Error (t->get_locus (),
6615 : "unrecognised token %qs in raw pointer type",
6616 : t->get_token_description ()));
6617 :
6618 0 : return nullptr;
6619 : }
6620 :
6621 : // parse type no bounds (required)
6622 8784 : std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
6623 8784 : if (type == nullptr)
6624 : {
6625 0 : Error error (lexer.peek_token ()->get_locus (),
6626 : "failed to parse pointed type of raw pointer type");
6627 0 : add_error (std::move (error));
6628 :
6629 0 : return nullptr;
6630 0 : }
6631 :
6632 : return std::unique_ptr<AST::RawPointerType> (
6633 8784 : new AST::RawPointerType (kind, std::move (type), locus));
6634 8784 : }
6635 :
6636 : /* Parses a slice or array type, depending on following arguments (as
6637 : * lookahead is not possible). */
6638 : template <typename ManagedTokenSource>
6639 : std::unique_ptr<AST::TypeNoBounds>
6640 2992 : Parser<ManagedTokenSource>::parse_slice_or_array_type ()
6641 : {
6642 2992 : location_t locus = lexer.peek_token ()->get_locus ();
6643 2992 : skip_token (LEFT_SQUARE);
6644 :
6645 : // parse inner type (required)
6646 2992 : std::unique_ptr<AST::Type> inner_type = parse_type ();
6647 2992 : if (inner_type == nullptr)
6648 : {
6649 0 : Error error (lexer.peek_token ()->get_locus (),
6650 : "failed to parse inner type in slice or array type");
6651 0 : add_error (std::move (error));
6652 :
6653 0 : return nullptr;
6654 0 : }
6655 :
6656 : // branch on next token
6657 2992 : const_TokenPtr t = lexer.peek_token ();
6658 2992 : switch (t->get_id ())
6659 : {
6660 1805 : case RIGHT_SQUARE:
6661 : // slice type
6662 1805 : lexer.skip_token ();
6663 :
6664 1805 : return std::unique_ptr<AST::SliceType> (
6665 1805 : new AST::SliceType (std::move (inner_type), locus));
6666 1187 : case SEMICOLON:
6667 : {
6668 : // array type
6669 1187 : lexer.skip_token ();
6670 :
6671 : // parse required array size expression
6672 1187 : auto size = parse_anon_const ();
6673 :
6674 1187 : if (!size)
6675 : {
6676 1 : Error error (lexer.peek_token ()->get_locus (),
6677 : "failed to parse size expression in array type");
6678 1 : add_error (std::move (error));
6679 :
6680 1 : return nullptr;
6681 1 : }
6682 :
6683 1186 : if (!skip_token (RIGHT_SQUARE))
6684 : {
6685 0 : return nullptr;
6686 : }
6687 :
6688 1186 : return std::unique_ptr<AST::ArrayType> (
6689 2359 : new AST::ArrayType (std::move (inner_type), std::move (*size),
6690 1186 : locus));
6691 1187 : }
6692 0 : default:
6693 : // error
6694 0 : add_error (
6695 0 : Error (t->get_locus (),
6696 : "unrecognised token %qs in slice or array type after inner type",
6697 : t->get_token_description ()));
6698 :
6699 0 : return nullptr;
6700 : }
6701 2992 : }
6702 :
6703 : // Parses a type, taking into account type boundary disambiguation.
6704 : template <typename ManagedTokenSource>
6705 : std::unique_ptr<AST::TypeNoBounds>
6706 32265 : Parser<ManagedTokenSource>::parse_type_no_bounds ()
6707 : {
6708 32265 : const_TokenPtr t = lexer.peek_token ();
6709 32265 : switch (t->get_id ())
6710 : {
6711 5 : case EXCLAM:
6712 : // never type - can't be macro as no path beforehand
6713 5 : lexer.skip_token ();
6714 5 : return std::unique_ptr<AST::NeverType> (
6715 5 : new AST::NeverType (t->get_locus ()));
6716 1462 : case LEFT_SQUARE:
6717 : // slice type or array type - requires further disambiguation
6718 1462 : return parse_slice_or_array_type ();
6719 26 : case LEFT_SHIFT:
6720 : case LEFT_ANGLE:
6721 : {
6722 : // qualified path in type
6723 26 : AST::QualifiedPathInType path = parse_qualified_path_in_type ();
6724 26 : if (path.is_error ())
6725 : {
6726 0 : Error error (t->get_locus (),
6727 : "failed to parse qualified path in type");
6728 0 : add_error (std::move (error));
6729 :
6730 0 : return nullptr;
6731 0 : }
6732 26 : return std::unique_ptr<AST::QualifiedPathInType> (
6733 26 : new AST::QualifiedPathInType (std::move (path)));
6734 26 : }
6735 225 : case UNDERSCORE:
6736 : // inferred type
6737 225 : lexer.skip_token ();
6738 225 : return std::unique_ptr<AST::InferredType> (
6739 225 : new AST::InferredType (t->get_locus ()));
6740 4894 : case ASTERISK:
6741 : // raw pointer type
6742 4894 : return parse_raw_pointer_type ();
6743 76 : case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
6744 : case LOGICAL_AND:
6745 : // reference type
6746 76 : return parse_reference_type ();
6747 0 : case LIFETIME:
6748 : /* probably a lifetime bound, so probably type param bounds in
6749 : * TraitObjectType. this is not allowed, but detection here for error
6750 : * message */
6751 0 : add_error (Error (t->get_locus (),
6752 : "lifetime bounds (i.e. in type param bounds, in "
6753 : "TraitObjectType) are not allowed as TypeNoBounds"));
6754 :
6755 0 : return nullptr;
6756 24996 : case IDENTIFIER:
6757 : case SUPER:
6758 : case SELF:
6759 : case SELF_ALIAS:
6760 : case CRATE:
6761 : case DOLLAR_SIGN:
6762 : case SCOPE_RESOLUTION:
6763 : {
6764 : // macro invocation or type path - requires further disambiguation.
6765 : /* for parsing path component of each rule, perhaps parse it as a
6766 : * typepath and attempt conversion to simplepath if a trailing '!' is
6767 : * found */
6768 : /* Type path also includes TraitObjectTypeOneBound BUT if it starts
6769 : * with it, it is exactly the same as a TypePath syntactically, so
6770 : * this is a syntactical ambiguity. As such, the parser will parse it
6771 : * as a TypePath. This, however, does not prevent TraitObjectType from
6772 : * starting with a typepath. */
6773 :
6774 : // parse path as type path
6775 24996 : AST::TypePath path = parse_type_path ();
6776 24996 : if (path.is_error ())
6777 : {
6778 0 : Error error (
6779 : t->get_locus (),
6780 : "failed to parse path as first component of type no bounds");
6781 0 : add_error (std::move (error));
6782 :
6783 0 : return nullptr;
6784 0 : }
6785 24996 : location_t locus = path.get_locus ();
6786 :
6787 : // branch on next token
6788 24996 : t = lexer.peek_token ();
6789 24996 : switch (t->get_id ())
6790 : {
6791 1 : case EXCLAM:
6792 : {
6793 : // macro invocation
6794 : // convert to simple path
6795 1 : AST::SimplePath macro_path = path.as_simple_path ();
6796 1 : if (macro_path.is_empty ())
6797 : {
6798 0 : Error error (t->get_locus (),
6799 : "failed to parse simple path in macro "
6800 : "invocation (for type)");
6801 0 : add_error (std::move (error));
6802 :
6803 0 : return nullptr;
6804 0 : }
6805 :
6806 1 : lexer.skip_token ();
6807 :
6808 1 : auto tok_tree = parse_delim_token_tree ();
6809 1 : if (!tok_tree)
6810 0 : return nullptr;
6811 :
6812 2 : return AST::MacroInvocation::Regular (
6813 2 : AST::MacroInvocData (std::move (macro_path),
6814 1 : std::move (tok_tree.value ())),
6815 1 : {}, locus);
6816 2 : }
6817 24995 : default:
6818 : // assume that this is a type path and not an error
6819 24995 : return std::unique_ptr<AST::TypePath> (
6820 24995 : new AST::TypePath (std::move (path)));
6821 : }
6822 24996 : }
6823 332 : case LEFT_PAREN:
6824 : /* tuple type or parenthesised type - requires further disambiguation
6825 : * (the usual). ok apparently can be a parenthesised TraitBound too, so
6826 : * could be TraitObjectTypeOneBound */
6827 332 : return parse_paren_prefixed_type_no_bounds ();
6828 2 : case FOR:
6829 : case ASYNC:
6830 : case CONST:
6831 : case UNSAFE:
6832 : case EXTERN_KW:
6833 : case FN_KW:
6834 : // bare function type (with no for lifetimes)
6835 2 : return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
6836 30 : case IMPL:
6837 30 : lexer.skip_token ();
6838 60 : if (lexer.peek_token ()->get_id () == LIFETIME)
6839 : {
6840 : /* cannot be one bound because lifetime prevents it from being
6841 : * traitbound not allowed as type no bounds, only here for error
6842 : * message */
6843 0 : Error error (
6844 0 : lexer.peek_token ()->get_locus (),
6845 : "lifetime (probably lifetime bound, in type param "
6846 : "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
6847 0 : add_error (std::move (error));
6848 :
6849 0 : return nullptr;
6850 0 : }
6851 : else
6852 : {
6853 : // should be trait bound, so parse trait bound
6854 30 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
6855 30 : if (initial_bound == nullptr)
6856 : {
6857 0 : Error error (lexer.peek_token ()->get_locus (),
6858 : "failed to parse ImplTraitTypeOneBound bound");
6859 0 : add_error (std::move (error));
6860 :
6861 0 : return nullptr;
6862 0 : }
6863 :
6864 30 : location_t locus = t->get_locus ();
6865 :
6866 : // ensure not a trait with multiple bounds
6867 30 : t = lexer.peek_token ();
6868 30 : if (t->get_id () == PLUS)
6869 : {
6870 0 : Error error (t->get_locus (),
6871 : "plus after trait bound means an ImplTraitType, "
6872 : "which is not allowed as a TypeNoBounds");
6873 0 : add_error (std::move (error));
6874 :
6875 0 : return nullptr;
6876 0 : }
6877 :
6878 30 : return std::unique_ptr<AST::ImplTraitTypeOneBound> (
6879 30 : new AST::ImplTraitTypeOneBound (std::move (initial_bound), locus));
6880 30 : }
6881 217 : case DYN:
6882 : case QUESTION_MARK:
6883 : {
6884 : // either TraitObjectTypeOneBound
6885 217 : bool has_dyn = false;
6886 217 : if (t->get_id () == DYN)
6887 : {
6888 217 : lexer.skip_token ();
6889 217 : has_dyn = true;
6890 : }
6891 :
6892 434 : if (lexer.peek_token ()->get_id () == LIFETIME)
6893 : {
6894 : /* means that cannot be TraitObjectTypeOneBound - so here for
6895 : * error message */
6896 0 : Error error (lexer.peek_token ()->get_locus (),
6897 : "lifetime as bound in TraitObjectTypeOneBound "
6898 : "is not allowed, so cannot be TypeNoBounds");
6899 0 : add_error (std::move (error));
6900 :
6901 0 : return nullptr;
6902 0 : }
6903 :
6904 : // should be trait bound, so parse trait bound
6905 217 : std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
6906 217 : if (initial_bound == nullptr)
6907 : {
6908 0 : Error error (
6909 0 : lexer.peek_token ()->get_locus (),
6910 : "failed to parse TraitObjectTypeOneBound initial bound");
6911 0 : add_error (std::move (error));
6912 :
6913 0 : return nullptr;
6914 0 : }
6915 :
6916 217 : location_t locus = t->get_locus ();
6917 :
6918 : // detect error with plus as next token
6919 217 : t = lexer.peek_token ();
6920 217 : if (t->get_id () == PLUS)
6921 : {
6922 0 : Error error (t->get_locus (),
6923 : "plus after trait bound means a TraitObjectType, "
6924 : "which is not allowed as a TypeNoBounds");
6925 0 : add_error (std::move (error));
6926 :
6927 0 : return nullptr;
6928 0 : }
6929 :
6930 : // convert trait bound to value object
6931 217 : AST::TraitBound value_bound (*initial_bound);
6932 :
6933 217 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
6934 434 : new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
6935 217 : has_dyn));
6936 217 : }
6937 0 : default:
6938 0 : add_error (Error (t->get_locus (),
6939 : "unrecognised token %qs in type no bounds",
6940 : t->get_token_description ()));
6941 :
6942 0 : return nullptr;
6943 : }
6944 32265 : }
6945 :
6946 : // Parses a type no bounds beginning with '('.
6947 : template <typename ManagedTokenSource>
6948 : std::unique_ptr<AST::TypeNoBounds>
6949 332 : Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
6950 : {
6951 : /* NOTE: this could probably be parsed without the HACK solution of
6952 : * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
6953 :
6954 : /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
6955 : * considered a trait bound, not a parenthesised type, so that it can still
6956 : * be used in type param bounds. */
6957 :
6958 332 : location_t left_paren_locus = lexer.peek_token ()->get_locus ();
6959 :
6960 : // skip left delim
6961 332 : lexer.skip_token ();
6962 : /* while next token isn't close delim, parse comma-separated types, saving
6963 : * whether trailing comma happens */
6964 332 : const_TokenPtr t = lexer.peek_token ();
6965 332 : bool trailing_comma = true;
6966 332 : std::vector<std::unique_ptr<AST::Type>> types;
6967 :
6968 967 : while (t->get_id () != RIGHT_PAREN)
6969 : {
6970 659 : std::unique_ptr<AST::Type> type = parse_type ();
6971 659 : if (type == nullptr)
6972 : {
6973 0 : Error error (t->get_locus (),
6974 : "failed to parse type inside parentheses (probably "
6975 : "tuple or parenthesised)");
6976 0 : add_error (std::move (error));
6977 :
6978 0 : return nullptr;
6979 0 : }
6980 659 : types.push_back (std::move (type));
6981 :
6982 659 : t = lexer.peek_token ();
6983 659 : if (t->get_id () != COMMA)
6984 : {
6985 24 : trailing_comma = false;
6986 : break;
6987 : }
6988 635 : lexer.skip_token ();
6989 :
6990 635 : t = lexer.peek_token ();
6991 : }
6992 :
6993 332 : if (!skip_token (RIGHT_PAREN))
6994 : {
6995 0 : return nullptr;
6996 : }
6997 :
6998 : // if only one type and no trailing comma, then not a tuple type
6999 332 : if (types.size () == 1 && !trailing_comma)
7000 : {
7001 : // must be a TraitObjectType (with more than one bound)
7002 26 : if (lexer.peek_token ()->get_id () == PLUS)
7003 : {
7004 : // error - this is not allowed for type no bounds
7005 0 : Error error (lexer.peek_token ()->get_locus (),
7006 : "plus (implying TraitObjectType as type param "
7007 : "bounds) is not allowed in type no bounds");
7008 0 : add_error (std::move (error));
7009 :
7010 0 : return nullptr;
7011 0 : }
7012 : else
7013 : {
7014 : // release vector pointer
7015 13 : std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
7016 : /* HACK: attempt to convert to trait bound. if fails, parenthesised
7017 : * type */
7018 13 : std::unique_ptr<AST::TraitBound> converted_bound (
7019 13 : released_ptr->to_trait_bound (true));
7020 13 : if (converted_bound == nullptr)
7021 : {
7022 : // parenthesised type
7023 13 : return std::unique_ptr<AST::ParenthesisedType> (
7024 13 : new AST::ParenthesisedType (std::move (released_ptr),
7025 13 : left_paren_locus));
7026 : }
7027 : else
7028 : {
7029 : // trait object type (one bound)
7030 :
7031 : // get value semantics trait bound
7032 0 : AST::TraitBound value_bound (*converted_bound);
7033 :
7034 0 : return std::unique_ptr<AST::TraitObjectTypeOneBound> (
7035 0 : new AST::TraitObjectTypeOneBound (value_bound,
7036 0 : left_paren_locus));
7037 0 : }
7038 13 : }
7039 : }
7040 : else
7041 : {
7042 319 : return std::unique_ptr<AST::TupleType> (
7043 319 : new AST::TupleType (std::move (types), left_paren_locus));
7044 : }
7045 : /* TODO: ensure that this ensures that dynamic dispatch for traits is not
7046 : * lost somehow */
7047 332 : }
7048 :
7049 : // Parses tuple struct items if they exist. Does not parse parentheses.
7050 : template <typename ManagedTokenSource>
7051 : std::unique_ptr<AST::TupleStructItems>
7052 2076 : Parser<ManagedTokenSource>::parse_tuple_struct_items ()
7053 : {
7054 2076 : std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
7055 :
7056 : // DEBUG
7057 2076 : rust_debug ("started parsing tuple struct items");
7058 :
7059 : // check for '..' at front
7060 4152 : if (lexer.peek_token ()->get_id () == DOT_DOT)
7061 : {
7062 : // only parse upper patterns
7063 25 : lexer.skip_token ();
7064 :
7065 : // DEBUG
7066 25 : rust_debug ("'..' at front in tuple struct items detected");
7067 :
7068 25 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
7069 :
7070 25 : const_TokenPtr t = lexer.peek_token ();
7071 42 : while (t->get_id () == COMMA)
7072 : {
7073 17 : lexer.skip_token ();
7074 :
7075 : // break if right paren
7076 34 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
7077 : break;
7078 :
7079 : // parse pattern, which is now required
7080 17 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
7081 17 : if (pattern == nullptr)
7082 : {
7083 0 : Error error (lexer.peek_token ()->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 17 : upper_patterns.push_back (std::move (pattern));
7090 :
7091 17 : t = lexer.peek_token ();
7092 : }
7093 :
7094 : // DEBUG
7095 25 : rust_debug (
7096 : "finished parsing tuple struct items ranged (upper/none only)");
7097 :
7098 25 : return std::unique_ptr<AST::TupleStructItemsHasRest> (
7099 25 : new AST::TupleStructItemsHasRest (std::move (lower_patterns),
7100 25 : std::move (upper_patterns)));
7101 25 : }
7102 :
7103 : // has at least some lower patterns
7104 2051 : const_TokenPtr t = lexer.peek_token ();
7105 2204 : while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
7106 : {
7107 : // DEBUG
7108 2148 : rust_debug ("about to parse pattern in tuple struct items");
7109 :
7110 : // parse pattern, which is required
7111 2148 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
7112 2148 : if (pattern == nullptr)
7113 : {
7114 0 : Error error (t->get_locus (),
7115 : "failed to parse pattern in tuple struct items");
7116 0 : add_error (std::move (error));
7117 :
7118 0 : return nullptr;
7119 0 : }
7120 2148 : lower_patterns.push_back (std::move (pattern));
7121 :
7122 : // DEBUG
7123 2148 : rust_debug ("successfully parsed pattern in tuple struct items");
7124 :
7125 4296 : if (lexer.peek_token ()->get_id () != COMMA)
7126 : {
7127 : // DEBUG
7128 1995 : rust_debug ("broke out of parsing patterns in tuple struct "
7129 : "items as no comma");
7130 :
7131 : break;
7132 : }
7133 153 : lexer.skip_token ();
7134 153 : t = lexer.peek_token ();
7135 : }
7136 :
7137 : // branch on next token
7138 2051 : t = lexer.peek_token ();
7139 2051 : switch (t->get_id ())
7140 : {
7141 2021 : case RIGHT_PAREN:
7142 2021 : return std::unique_ptr<AST::TupleStructItemsNoRest> (
7143 2021 : new AST::TupleStructItemsNoRest (std::move (lower_patterns)));
7144 29 : case DOT_DOT:
7145 : {
7146 : // has an upper range that must be parsed separately
7147 29 : lexer.skip_token ();
7148 :
7149 29 : std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
7150 :
7151 29 : t = lexer.peek_token ();
7152 35 : while (t->get_id () == COMMA)
7153 : {
7154 6 : lexer.skip_token ();
7155 :
7156 : // break if next token is right paren
7157 12 : if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
7158 : break;
7159 :
7160 : // parse pattern, which is required
7161 6 : std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
7162 6 : if (pattern == nullptr)
7163 : {
7164 0 : Error error (lexer.peek_token ()->get_locus (),
7165 : "failed to parse pattern in tuple struct items");
7166 0 : add_error (std::move (error));
7167 :
7168 0 : return nullptr;
7169 0 : }
7170 6 : upper_patterns.push_back (std::move (pattern));
7171 :
7172 6 : t = lexer.peek_token ();
7173 : }
7174 :
7175 29 : return std::unique_ptr<AST::TupleStructItemsHasRest> (
7176 29 : new AST::TupleStructItemsHasRest (std::move (lower_patterns),
7177 29 : std::move (upper_patterns)));
7178 29 : }
7179 1 : default:
7180 : // error
7181 1 : add_error (Error (t->get_locus (),
7182 : "unexpected token %qs in tuple struct items",
7183 : t->get_token_description ()));
7184 :
7185 1 : return nullptr;
7186 : }
7187 2076 : }
7188 :
7189 : /* Parses a statement or expression (depending on whether a trailing semicolon
7190 : * exists). Useful for block expressions where it cannot be determined through
7191 : * lookahead whether it is a statement or expression to be parsed. */
7192 : template <typename ManagedTokenSource>
7193 : tl::expected<ExprOrStmt, Parse::Error::Node>
7194 80902 : Parser<ManagedTokenSource>::parse_stmt_or_expr ()
7195 : {
7196 : // quick exit for empty statement
7197 80902 : const_TokenPtr t = lexer.peek_token ();
7198 80902 : if (t->get_id () == SEMICOLON)
7199 : {
7200 18 : lexer.skip_token ();
7201 18 : std::unique_ptr<AST::EmptyStmt> stmt (
7202 18 : new AST::EmptyStmt (t->get_locus ()));
7203 36 : return ExprOrStmt (std::move (stmt));
7204 18 : }
7205 :
7206 : // parse outer attributes
7207 80884 : AST::AttrVec outer_attrs = parse_outer_attributes ();
7208 80884 : ParseRestrictions restrictions;
7209 80884 : restrictions.expr_can_be_stmt = true;
7210 :
7211 : // Defered child error checking: we need to check for a semicolon
7212 80884 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr> expr;
7213 :
7214 : // parsing this will be annoying because of the many different possibilities
7215 : /* best may be just to copy paste in parse_item switch, and failing that try
7216 : * to parse outer attributes, and then pass them in to either a let
7217 : * statement or (fallback) expression statement. */
7218 : // FIXME: think of a way to do this without such a large switch?
7219 :
7220 : /* FIXME: for expressions at least, the only way that they can really be
7221 : * parsed properly in this way is if they don't support operators on them.
7222 : * They must be pratt-parsed otherwise. As such due to composability, only
7223 : * explicit statements will have special cases here. This should roughly
7224 : * correspond to "expr-with-block", but this warning is here in case it
7225 : * isn't the case. */
7226 80884 : t = lexer.peek_token ();
7227 80884 : switch (t->get_id ())
7228 : {
7229 24483 : case LET:
7230 : {
7231 : // let statement
7232 24483 : std::unique_ptr<AST::LetStmt> stmt (
7233 24483 : parse_let_stmt (std::move (outer_attrs)));
7234 48966 : return ExprOrStmt (std::move (stmt));
7235 24483 : }
7236 967 : case PUB:
7237 : case MOD:
7238 : case EXTERN_KW:
7239 : case USE:
7240 : case FN_KW:
7241 : case TYPE:
7242 : case STRUCT_KW:
7243 : case ENUM_KW:
7244 : case CONST:
7245 : case STATIC_KW:
7246 : case AUTO:
7247 : case TRAIT:
7248 : case IMPL:
7249 : {
7250 967 : std::unique_ptr<AST::VisItem> item (
7251 967 : parse_vis_item (std::move (outer_attrs)));
7252 1934 : return ExprOrStmt (std::move (item));
7253 967 : }
7254 : /* TODO: implement union keyword but not really because of
7255 : * context-dependence crappy hack way to parse a union written below to
7256 : * separate it from the good code. */
7257 : // case UNION:
7258 4721 : case UNSAFE:
7259 : { // maybe - unsafe traits are a thing
7260 : /* if any of these (should be all possible VisItem prefixes), parse a
7261 : * VisItem - can't parse item because would require reparsing outer
7262 : * attributes */
7263 4721 : const_TokenPtr t2 = lexer.peek_token (1);
7264 4721 : switch (t2->get_id ())
7265 : {
7266 4698 : case LEFT_CURLY:
7267 : {
7268 : // unsafe block: parse as expression
7269 9396 : expr = parse_expr (std::move (outer_attrs), restrictions);
7270 : break;
7271 : }
7272 0 : case AUTO:
7273 : case TRAIT:
7274 : {
7275 : // unsafe trait
7276 0 : std::unique_ptr<AST::VisItem> item (
7277 0 : parse_vis_item (std::move (outer_attrs)));
7278 0 : return ExprOrStmt (std::move (item));
7279 0 : }
7280 23 : case EXTERN_KW:
7281 : case FN_KW:
7282 : {
7283 : // unsafe function
7284 23 : std::unique_ptr<AST::VisItem> item (
7285 23 : parse_vis_item (std::move (outer_attrs)));
7286 46 : return ExprOrStmt (std::move (item));
7287 23 : }
7288 0 : case IMPL:
7289 : {
7290 : // unsafe trait impl
7291 0 : std::unique_ptr<AST::VisItem> item (
7292 0 : parse_vis_item (std::move (outer_attrs)));
7293 0 : return ExprOrStmt (std::move (item));
7294 0 : }
7295 0 : default:
7296 0 : add_error (Error (t2->get_locus (),
7297 : "unrecognised token %qs after parsing unsafe - "
7298 : "expected beginning of expression or statement",
7299 : t->get_token_description ()));
7300 :
7301 : // skip somewhere?
7302 : return tl::unexpected<Parse::Error::Node> (
7303 0 : Parse::Error::Node::MALFORMED);
7304 : }
7305 : break;
7306 62739 : }
7307 : /* FIXME: this is either a macro invocation or macro invocation semi.
7308 : * start parsing to determine which one it is. */
7309 : // FIXME: old code there
7310 :
7311 : // crappy hack to do union "keyword"
7312 29025 : case IDENTIFIER:
7313 29025 : if (t->get_str () == Values::WeakKeywords::UNION
7314 29061 : && lexer.peek_token (1)->get_id () == IDENTIFIER)
7315 : {
7316 1 : std::unique_ptr<AST::VisItem> item (
7317 1 : parse_vis_item (std::move (outer_attrs)));
7318 2 : return ExprOrStmt (std::move (item));
7319 : // or should this go straight to parsing union?
7320 1 : }
7321 29024 : else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
7322 29541 : && lexer.peek_token (1)->get_id () == EXCLAM)
7323 : {
7324 : // macro_rules! macro item
7325 517 : std::unique_ptr<AST::Item> item (
7326 517 : parse_macro_rules_def (std::move (outer_attrs)));
7327 1034 : return ExprOrStmt (std::move (item));
7328 517 : }
7329 : gcc_fallthrough ();
7330 : case SUPER:
7331 : case SELF:
7332 : case SELF_ALIAS:
7333 : case CRATE:
7334 : case SCOPE_RESOLUTION:
7335 : case DOLLAR_SIGN:
7336 : {
7337 34967 : AST::PathInExpression path = parse_path_in_expression ();
7338 : tl::expected<std::unique_ptr<AST::Expr>, Parse::Error::Expr>
7339 34967 : null_denotation;
7340 :
7341 69934 : if (lexer.peek_token ()->get_id () == EXCLAM)
7342 : {
7343 2704 : std::unique_ptr<AST::MacroInvocation> invoc
7344 5408 : = parse_macro_invocation_partial (std::move (path),
7345 : std::move (outer_attrs));
7346 2704 : if (invoc == nullptr)
7347 : return tl::unexpected<Parse::Error::Node> (
7348 0 : Parse::Error::Node::CHILD_ERROR);
7349 :
7350 2704 : if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
7351 : {
7352 1516 : invoc->add_semicolon ();
7353 : // Macro invocation with semicolon.
7354 1516 : return ExprOrStmt (
7355 3032 : std::unique_ptr<AST::Stmt> (std::move (invoc)));
7356 : }
7357 :
7358 2376 : TokenId after_macro = lexer.peek_token ()->get_id ();
7359 :
7360 1188 : AST::DelimType delim_type = invoc->get_invoc_data ()
7361 1188 : .get_delim_tok_tree ()
7362 1188 : .get_delim_type ();
7363 :
7364 1188 : if (delim_type == AST::CURLY && after_macro != DOT
7365 20 : && after_macro != QUESTION_MARK)
7366 : {
7367 20 : rust_debug ("braced macro statement");
7368 20 : return ExprOrStmt (
7369 40 : std::unique_ptr<AST::Stmt> (std::move (invoc)));
7370 : }
7371 :
7372 1168 : null_denotation = std::move (invoc);
7373 2704 : }
7374 : else
7375 : {
7376 : null_denotation
7377 64525 : = null_denotation_path (std::move (path), {}, restrictions);
7378 : }
7379 :
7380 133718 : expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
7381 : std::move (outer_attrs), restrictions);
7382 : break;
7383 34967 : }
7384 15228 : default:
7385 : /* expression statement or expression itself - parse
7386 : * expression then make it statement if semi afterwards */
7387 30426 : expr = parse_expr (std::move (outer_attrs), restrictions);
7388 15228 : break;
7389 : }
7390 :
7391 53357 : const_TokenPtr after_expr = lexer.peek_token ();
7392 53357 : if (after_expr->get_id () == SEMICOLON)
7393 : {
7394 : // must be expression statement
7395 14810 : lexer.skip_token ();
7396 :
7397 14810 : if (expr)
7398 : {
7399 14809 : return ExprOrStmt (
7400 29618 : std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
7401 44427 : t->get_locus (), true));
7402 : }
7403 : else
7404 : {
7405 : return tl::unexpected<Parse::Error::Node> (
7406 1 : Parse::Error::Node::CHILD_ERROR);
7407 : }
7408 : }
7409 :
7410 38547 : if (expr)
7411 : {
7412 : // block expression statement.
7413 38515 : if (!expr.value ()->is_expr_without_block ()
7414 38515 : && after_expr->get_id () != RIGHT_CURLY)
7415 3614 : return ExprOrStmt (
7416 7228 : std::make_unique<AST::ExprStmt> (std::move (expr.value ()),
7417 10842 : t->get_locus (), false));
7418 :
7419 : // Check if expr_without_block is properly terminated
7420 34901 : if (expr.value ()->is_expr_without_block ()
7421 34901 : && after_expr->get_id () != RIGHT_CURLY)
7422 : {
7423 : // expr_without_block must be followed by ';' or '}'
7424 1 : Error error (after_expr->get_locus (),
7425 : "expected %<;%> or %<}%> after expression, found %qs",
7426 : after_expr->get_token_description ());
7427 1 : add_error (std::move (error));
7428 : return tl::unexpected<Parse::Error::Node> (
7429 1 : Parse::Error::Node::MALFORMED);
7430 1 : }
7431 : }
7432 :
7433 : // return expression
7434 34932 : if (expr)
7435 69800 : return ExprOrStmt (std::move (expr.value ()));
7436 : else
7437 32 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
7438 134241 : }
7439 :
7440 : } // namespace Rust
7441 :
7442 : #include "rust-parse-impl-utils.hxx"
7443 : #include "rust-parse-impl-attribute.hxx"
7444 : #include "rust-parse-impl-ttree.hxx"
7445 : #include "rust-parse-impl-macro.hxx"
7446 : #include "rust-parse-impl-path.hxx"
7447 : #include "rust-parse-impl-pattern.hxx"
7448 : #include "rust-parse-impl-expr.hxx"
|