]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/parse/rust-parse-impl.h
LoongArch: Fix wrong code generated by TARGET_VECTORIZE_VEC_PERM_CONST [PR121064]
[thirdparty/gcc.git] / gcc / rust / parse / rust-parse-impl.h
CommitLineData
6441eb6d 1// Copyright (C) 2020-2025 Free Software Foundation, Inc.
35e4f3b4
JP
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 with rust-parse.h
23 * This is also the reason why there are no include guards. */
24
7a4c2f8e 25#include "rust-common.h"
7a989394 26#include "rust-expr.h"
ceed844b 27#include "rust-item.h"
12844c82 28#include "rust-common.h"
dff99b74 29#include "rust-token.h"
35e4f3b4
JP
30#define INCLUDE_ALGORITHM
31#include "rust-diagnostics.h"
e6d40678 32#include "rust-dir-owner.h"
fc024ea7 33#include "rust-attribute-values.h"
b5265142 34#include "rust-keyword-values.h"
e06530a5 35#include "rust-edition.h"
35e4f3b4 36
6b8365a9
OA
37#include "optional.h"
38
35e4f3b4
JP
39namespace Rust {
40// Left binding powers of operations.
41enum binding_powers
42{
43 // Highest priority
44 LBP_HIGHEST = 100,
45
46 LBP_PATH = 95,
47
48 LBP_METHOD_CALL = 90,
49
50 LBP_FIELD_EXPR = 85,
51
52 LBP_FUNCTION_CALL = 80,
53 LBP_ARRAY_REF = LBP_FUNCTION_CALL,
54
55 LBP_QUESTION_MARK = 75, // unary postfix - counts as left
56
57 LBP_UNARY_PLUS = 70, // Used only when the null denotation is +
58 LBP_UNARY_MINUS = LBP_UNARY_PLUS, // Used only when the null denotation is -
59 LBP_UNARY_ASTERISK = LBP_UNARY_PLUS, // deref operator - unary prefix
60 LBP_UNARY_EXCLAM = LBP_UNARY_PLUS,
61 LBP_UNARY_AMP = LBP_UNARY_PLUS,
62 LBP_UNARY_AMP_MUT = LBP_UNARY_PLUS,
63
64 LBP_AS = 65,
65
66 LBP_MUL = 60,
67 LBP_DIV = LBP_MUL,
68 LBP_MOD = LBP_MUL,
69
70 LBP_PLUS = 55,
71 LBP_MINUS = LBP_PLUS,
72
73 LBP_L_SHIFT = 50,
74 LBP_R_SHIFT = LBP_L_SHIFT,
75
76 LBP_AMP = 45,
77
78 LBP_CARET = 40,
79
80 LBP_PIPE = 35,
81
82 LBP_EQUAL = 30,
83 LBP_NOT_EQUAL = LBP_EQUAL,
84 LBP_SMALLER_THAN = LBP_EQUAL,
85 LBP_SMALLER_EQUAL = LBP_EQUAL,
86 LBP_GREATER_THAN = LBP_EQUAL,
87 LBP_GREATER_EQUAL = LBP_EQUAL,
88
89 LBP_LOGICAL_AND = 25,
90
91 LBP_LOGICAL_OR = 20,
92
93 LBP_DOT_DOT = 15,
94 LBP_DOT_DOT_EQ = LBP_DOT_DOT,
95
96 // TODO: note all these assig operators are RIGHT associative!
97 LBP_ASSIG = 10,
98 LBP_PLUS_ASSIG = LBP_ASSIG,
99 LBP_MINUS_ASSIG = LBP_ASSIG,
100 LBP_MULT_ASSIG = LBP_ASSIG,
101 LBP_DIV_ASSIG = LBP_ASSIG,
102 LBP_MOD_ASSIG = LBP_ASSIG,
103 LBP_AMP_ASSIG = LBP_ASSIG,
104 LBP_PIPE_ASSIG = LBP_ASSIG,
105 LBP_CARET_ASSIG = LBP_ASSIG,
106 LBP_L_SHIFT_ASSIG = LBP_ASSIG,
107 LBP_R_SHIFT_ASSIG = LBP_ASSIG,
108
109 // return, break, and closures as lowest priority?
110 LBP_RETURN = 5,
111 LBP_BREAK = LBP_RETURN,
112 LBP_CLOSURE = LBP_RETURN, // unary prefix operators
113
114#if 0
115 // rust precedences
116 // used for closures
117 PREC_CLOSURE = -40,
118 // used for break, continue, return, and yield
119 PREC_JUMP = -30,
120 // used for range (although weird comment in rustc about this)
121 PREC_RANGE = -10,
122 // used for binary operators mentioned below - also cast, colon (type),
123 // assign, assign_op
124 PREC_BINOP = FROM_ASSOC_OP,
125 // used for box, address_of, let, unary (again, weird comment on let)
126 PREC_PREFIX = 50,
127 // used for await, call, method call, field, index, try,
128 // inline asm, macro invocation
129 PREC_POSTFIX = 60,
130 // used for array, repeat, tuple, literal, path, paren, if,
131 // while, for, 'loop', match, block, try block, async, struct
132 PREC_PAREN = 99,
133 PREC_FORCE_PAREN = 100,
134#endif
135
136 // lowest priority
137 LBP_LOWEST = 0
138};
139
140/* Returns whether the token can start a type (i.e. there is a valid type
141 * beginning with the token). */
142inline bool
143can_tok_start_type (TokenId id)
144{
145 switch (id)
146 {
147 case EXCLAM:
148 case LEFT_SQUARE:
149 case LEFT_ANGLE:
150 case UNDERSCORE:
151 case ASTERISK:
152 case AMP:
153 case LIFETIME:
154 case IDENTIFIER:
155 case SUPER:
156 case SELF:
157 case SELF_ALIAS:
158 case CRATE:
159 case DOLLAR_SIGN:
160 case SCOPE_RESOLUTION:
161 case LEFT_PAREN:
162 case FOR:
163 case ASYNC:
164 case CONST:
165 case UNSAFE:
7f631967
PEP
166 case EXTERN_KW:
167 case FN_KW:
35e4f3b4
JP
168 case IMPL:
169 case DYN:
170 case QUESTION_MARK:
171 return true;
172 default:
173 return false;
174 }
175}
176
177/* Returns whether the token id is (or is likely to be) a right angle bracket.
178 * i.e. '>', '>>', '>=' and '>>=' tokens. */
179inline bool
180is_right_angle_tok (TokenId id)
181{
182 switch (id)
183 {
184 case RIGHT_ANGLE:
185 case RIGHT_SHIFT:
186 case GREATER_OR_EQUAL:
187 case RIGHT_SHIFT_EQ:
188 return true;
189 default:
190 return false;
191 }
192}
193
194/* HACK-y special handling for skipping a right angle token at the end of
195 * generic arguments.
196 * Currently, this replaces the "current token" with one that is identical
197 * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad
198 * for several reasons - it modifies the token stream to something that
199 * actually doesn't make syntactic sense, it may not worked if the token
200 * has already been skipped, etc. It was done because it would not
201 * actually require inserting new items into the token stream (which I
202 * thought would take more work to not mess up) and because I wasn't sure
203 * if the "already seen right angle" flag in the parser would work
204 * correctly.
205 * Those two other approaches listed are in my opinion actually better
206 * long-term - insertion is probably best as it reflects syntactically
207 * what occurs. On the other hand, I need to do a code audit to make sure
208 * that insertion doesn't mess anything up. So that's a FIXME. */
209template <typename ManagedTokenSource>
210bool
211Parser<ManagedTokenSource>::skip_generics_right_angle ()
212{
213 /* OK, new great idea. Have a lexer method called
214 * "split_current_token(TokenType newLeft, TokenType newRight)", which is
215 * called here with whatever arguments are appropriate. That lexer method
216 * handles "replacing" the current token with the "newLeft" and "inserting"
217 * the next token with the "newRight" (and creating a location, etc. for it)
218 */
219
220 /* HACK: special handling for right shift '>>', greater or equal '>=', and
221 * right shift assig */
222 // '>>='
223 const_TokenPtr tok = lexer.peek_token ();
224 switch (tok->get_id ())
225 {
226 case RIGHT_ANGLE:
227 // this is good - skip token
228 lexer.skip_token ();
229 return true;
230 case RIGHT_SHIFT: {
231 // new implementation that should be better
232 lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE);
233 lexer.skip_token ();
234 return true;
235 }
236 case GREATER_OR_EQUAL: {
237 // new implementation that should be better
238 lexer.split_current_token (RIGHT_ANGLE, EQUAL);
239 lexer.skip_token ();
240 return true;
241 }
242 case RIGHT_SHIFT_EQ: {
243 // new implementation that should be better
244 lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL);
245 lexer.skip_token ();
246 return true;
247 }
248 default:
249 add_error (Error (tok->get_locus (),
250 "expected %<>%> at end of generic argument - found %qs",
251 tok->get_token_description ()));
252 return false;
253 }
254}
255
256/* Gets left binding power for specified token.
257 * Not suitable for use at the moment or possibly ever because binding power
258 * cannot be purely determined from operator token with Rust grammar - e.g.
259 * method call and field access have
260 * different left binding powers but the same operator token. */
261template <typename ManagedTokenSource>
262int
263Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
264{
265 // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
266 switch (token->get_id ())
267 {
268 /* TODO: issue here - distinguish between method calls and field access
269 * somehow? Also would have to distinguish between paths and function
270 * calls (:: operator), maybe more stuff. */
271 /* Current plan for tackling LBP - don't do it based on token, use
272 * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr
273 * and handle other expressions without it. rustc only considers
274 * arithmetic, logical/relational, 'as',
275 * '?=', ranges, colons, and assignment to have operator precedence and
276 * associativity rules applicable. It then has
277 * a separate "ExprPrecedence" that also includes binary operators. */
278
279 // TODO: handle operator overloading - have a function replace the
280 // operator?
281
282 /*case DOT:
283 return LBP_DOT;*/
284
285 case SCOPE_RESOLUTION:
286 rust_debug (
287 "possible error - looked up LBP of scope resolution operator. should "
288 "be handled elsewhere.");
289 return LBP_PATH;
290
291 /* Resolved by lookahead HACK that should work with current code. If next
292 * token is identifier and token after that isn't parenthesised expression
293 * list, it is a field reference. */
294 case DOT:
295 if (lexer.peek_token (1)->get_id () == IDENTIFIER
296 && lexer.peek_token (2)->get_id () != LEFT_PAREN)
297 {
298 return LBP_FIELD_EXPR;
299 }
300 return LBP_METHOD_CALL;
301
302 case LEFT_PAREN:
303 return LBP_FUNCTION_CALL;
304
305 case LEFT_SQUARE:
306 return LBP_ARRAY_REF;
307
308 // postfix question mark (i.e. error propagation expression)
309 case QUESTION_MARK:
310 return LBP_QUESTION_MARK;
311
312 case AS:
313 return LBP_AS;
314
315 case ASTERISK:
316 return LBP_MUL;
317 case DIV:
318 return LBP_DIV;
319 case PERCENT:
320 return LBP_MOD;
321
322 case PLUS:
323 return LBP_PLUS;
324 case MINUS:
325 return LBP_MINUS;
326
327 case LEFT_SHIFT:
328 return LBP_L_SHIFT;
329 case RIGHT_SHIFT:
330 return LBP_R_SHIFT;
331
332 // binary & operator
333 case AMP:
334 return LBP_AMP;
335
336 // binary ^ operator
337 case CARET:
338 return LBP_CARET;
339
340 // binary | operator
341 case PIPE:
342 return LBP_PIPE;
343
344 case EQUAL_EQUAL:
345 return LBP_EQUAL;
346 case NOT_EQUAL:
347 return LBP_NOT_EQUAL;
348 case RIGHT_ANGLE:
349 return LBP_GREATER_THAN;
350 case GREATER_OR_EQUAL:
351 return LBP_GREATER_EQUAL;
352 case LEFT_ANGLE:
353 return LBP_SMALLER_THAN;
354 case LESS_OR_EQUAL:
355 return LBP_SMALLER_EQUAL;
356
357 case LOGICAL_AND:
358 return LBP_LOGICAL_AND;
359
360 case OR:
361 return LBP_LOGICAL_OR;
362
363 case DOT_DOT:
364 return LBP_DOT_DOT;
365
366 case DOT_DOT_EQ:
367 return LBP_DOT_DOT_EQ;
368
369 case EQUAL:
370 return LBP_ASSIG;
371 case PLUS_EQ:
372 return LBP_PLUS_ASSIG;
373 case MINUS_EQ:
374 return LBP_MINUS_ASSIG;
375 case ASTERISK_EQ:
376 return LBP_MULT_ASSIG;
377 case DIV_EQ:
378 return LBP_DIV_ASSIG;
379 case PERCENT_EQ:
380 return LBP_MOD_ASSIG;
381 case AMP_EQ:
382 return LBP_AMP_ASSIG;
383 case PIPE_EQ:
384 return LBP_PIPE_ASSIG;
385 case CARET_EQ:
386 return LBP_CARET_ASSIG;
387 case LEFT_SHIFT_EQ:
388 return LBP_L_SHIFT_ASSIG;
389 case RIGHT_SHIFT_EQ:
390 return LBP_R_SHIFT_ASSIG;
391
392 /* HACK: float literal due to lexer misidentifying a dot then an integer as
393 * a float */
394 case FLOAT_LITERAL:
395 return LBP_FIELD_EXPR;
396 // field expr is same as tuple expr in precedence, i imagine
397 // TODO: is this needed anymore? lexer shouldn't do that anymore
398
399 // anything that can't appear in an infix position is given lowest priority
400 default:
401 return LBP_LOWEST;
402 }
403}
404
405// Returns true when current token is EOF.
406template <typename ManagedTokenSource>
407bool
408Parser<ManagedTokenSource>::done_end_of_file ()
409{
410 return lexer.peek_token ()->get_id () == END_OF_FILE;
411}
412
413// Parses a sequence of items within a module or the implicit top-level module
414// in a crate
415template <typename ManagedTokenSource>
416std::vector<std::unique_ptr<AST::Item>>
417Parser<ManagedTokenSource>::parse_items ()
418{
419 std::vector<std::unique_ptr<AST::Item>> items;
420
421 const_TokenPtr t = lexer.peek_token ();
422 while (t->get_id () != END_OF_FILE)
423 {
424 std::unique_ptr<AST::Item> item = parse_item (false);
425 if (item == nullptr)
426 {
427 Error error (lexer.peek_token ()->get_locus (),
428 "failed to parse item in crate");
429 add_error (std::move (error));
430
431 // TODO: should all items be cleared?
432 items = std::vector<std::unique_ptr<AST::Item>> ();
433 break;
434 }
435
436 items.push_back (std::move (item));
437
438 t = lexer.peek_token ();
439 }
440
441 return items;
442}
443
444// Parses a crate (compilation unit) - entry point
445template <typename ManagedTokenSource>
446std::unique_ptr<AST::Crate>
447Parser<ManagedTokenSource>::parse_crate ()
448{
449 // parse inner attributes
450 AST::AttrVec inner_attrs = parse_inner_attributes ();
451
452 // parse items
453 std::vector<std::unique_ptr<AST::Item>> items = parse_items ();
454
455 // emit all errors
456 for (const auto &error : error_table)
2785d591 457 error.emit ();
35e4f3b4
JP
458
459 return std::unique_ptr<AST::Crate> (
460 new AST::Crate (std::move (items), std::move (inner_attrs)));
461}
462
463// Parse a contiguous block of inner attributes.
464template <typename ManagedTokenSource>
465AST::AttrVec
466Parser<ManagedTokenSource>::parse_inner_attributes ()
467{
468 AST::AttrVec inner_attributes;
469
470 // only try to parse it if it starts with "#!" not only "#"
471 while ((lexer.peek_token ()->get_id () == HASH
472 && lexer.peek_token (1)->get_id () == EXCLAM)
473 || lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
474 {
475 AST::Attribute inner_attr = parse_inner_attribute ();
476
477 /* Ensure only valid inner attributes are added to the inner_attributes
478 * list */
479 if (!inner_attr.is_empty ())
480 {
481 inner_attributes.push_back (std::move (inner_attr));
482 }
483 else
484 {
485 /* If no more valid inner attributes, break out of loop (only
486 * contiguous inner attributes parsed). */
487 break;
488 }
489 }
490
491 inner_attributes.shrink_to_fit ();
492 return inner_attributes;
493}
494
495// Parse a inner or outer doc comment into an doc attribute
496template <typename ManagedTokenSource>
80c68893 497std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
35e4f3b4
JP
498Parser<ManagedTokenSource>::parse_doc_comment ()
499{
500 const_TokenPtr token = lexer.peek_token ();
d991a3f1 501 location_t locus = token->get_locus ();
fc024ea7 502 AST::SimplePathSegment segment (Values::Attributes::DOC, locus);
35e4f3b4
JP
503 std::vector<AST::SimplePathSegment> segments;
504 segments.push_back (std::move (segment));
505 AST::SimplePath attr_path (std::move (segments), false, locus);
506 AST::LiteralExpr lit_expr (token->get_str (), AST::Literal::STRING,
507 PrimitiveCoreType::CORETYPE_STR, {}, locus);
508 std::unique_ptr<AST::AttrInput> attr_input (
509 new AST::AttrInputLiteral (std::move (lit_expr)));
510 lexer.skip_token ();
9a7a79eb 511 return std::make_tuple (std::move (attr_path), std::move (attr_input), locus);
35e4f3b4
JP
512}
513
514// Parse a single inner attribute.
515template <typename ManagedTokenSource>
516AST::Attribute
517Parser<ManagedTokenSource>::parse_inner_attribute ()
518{
519 if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
9a7a79eb
PEP
520 {
521 auto values = parse_doc_comment ();
522 auto path = std::move (std::get<0> (values));
523 auto input = std::move (std::get<1> (values));
524 auto loc = std::get<2> (values);
525 return AST::Attribute (std::move (path), std::move (input), loc, true);
526 }
35e4f3b4
JP
527
528 if (lexer.peek_token ()->get_id () != HASH)
529 {
530 Error error (lexer.peek_token ()->get_locus (),
531 "BUG: token %<#%> is missing, but %<parse_inner_attribute%> "
532 "was invoked");
533 add_error (std::move (error));
534
535 return AST::Attribute::create_empty ();
536 }
537 lexer.skip_token ();
538
539 if (lexer.peek_token ()->get_id () != EXCLAM)
540 {
541 Error error (lexer.peek_token ()->get_locus (),
542 "expected %<!%> or %<[%> for inner attribute");
543 add_error (std::move (error));
544
545 return AST::Attribute::create_empty ();
546 }
547 lexer.skip_token ();
548
549 if (!skip_token (LEFT_SQUARE))
550 return AST::Attribute::create_empty ();
551
9a7a79eb
PEP
552 auto values = parse_attribute_body ();
553
554 auto path = std::move (std::get<0> (values));
555 auto input = std::move (std::get<1> (values));
556 auto loc = std::get<2> (values);
557 auto actual_attribute
558 = AST::Attribute (std::move (path), std::move (input), loc, true);
35e4f3b4
JP
559
560 if (!skip_token (RIGHT_SQUARE))
561 return AST::Attribute::create_empty ();
562
563 return actual_attribute;
564}
565
566// Parses the body of an attribute (inner or outer).
567template <typename ManagedTokenSource>
80c68893 568std::tuple<AST::SimplePath, std::unique_ptr<AST::AttrInput>, location_t>
35e4f3b4
JP
569Parser<ManagedTokenSource>::parse_attribute_body ()
570{
d991a3f1 571 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
572
573 AST::SimplePath attr_path = parse_simple_path ();
574 // ensure path is valid to parse attribute input
575 if (attr_path.is_empty ())
576 {
577 Error error (lexer.peek_token ()->get_locus (),
578 "empty simple path in attribute");
579 add_error (std::move (error));
580
581 // Skip past potential further info in attribute (i.e. attr_input)
582 skip_after_end_attribute ();
1678cdd3 583 return std::make_tuple (std::move (attr_path), nullptr, UNDEF_LOCATION);
35e4f3b4
JP
584 }
585
586 std::unique_ptr<AST::AttrInput> attr_input = parse_attr_input ();
587 // AttrInput is allowed to be null, so no checks here
588
9a7a79eb 589 return std::make_tuple (std::move (attr_path), std::move (attr_input), locus);
35e4f3b4
JP
590}
591
592/* Determines whether token is a valid simple path segment. This does not
593 * include scope resolution operators. */
594inline bool
595is_simple_path_segment (TokenId id)
596{
597 switch (id)
598 {
599 case IDENTIFIER:
600 case SUPER:
601 case SELF:
602 case CRATE:
603 return true;
604 case DOLLAR_SIGN:
605 // assume that dollar sign leads to $crate
606 return true;
607 default:
608 return false;
609 }
610}
611
612// Parses a SimplePath AST node, if it exists. Does nothing otherwise.
613template <typename ManagedTokenSource>
614AST::SimplePath
615Parser<ManagedTokenSource>::parse_simple_path ()
616{
617 bool has_opening_scope_resolution = false;
d991a3f1 618 location_t locus = UNKNOWN_LOCATION;
35e4f3b4
JP
619
620 // don't parse anything if not a path upfront
621 if (!is_simple_path_segment (lexer.peek_token ()->get_id ())
622 && !is_simple_path_segment (lexer.peek_token (1)->get_id ()))
623 return AST::SimplePath::create_empty ();
624
625 /* Checks for opening scope resolution (i.e. global scope fully-qualified
626 * path) */
627 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
628 {
629 has_opening_scope_resolution = true;
630
631 locus = lexer.peek_token ()->get_locus ();
632
633 lexer.skip_token ();
634 }
635
636 // Parse single required simple path segment
637 AST::SimplePathSegment segment = parse_simple_path_segment ();
638
639 // get location if not gotten already
e5f3ad0f 640 if (locus == UNKNOWN_LOCATION)
35e4f3b4
JP
641 locus = segment.get_locus ();
642
643 std::vector<AST::SimplePathSegment> segments;
644
645 // Return empty vector if first, actually required segment is an error
646 if (segment.is_error ())
647 return AST::SimplePath::create_empty ();
648
649 segments.push_back (std::move (segment));
650
651 // Parse all other simple path segments
652 while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
653 {
654 // Skip scope resolution operator
655 lexer.skip_token ();
656
657 AST::SimplePathSegment new_segment = parse_simple_path_segment ();
658
659 // Return path as currently constructed if segment in error state.
660 if (new_segment.is_error ())
661 break;
662
663 segments.push_back (std::move (new_segment));
664 }
665
666 // DEBUG: check for any empty segments
667 for (const auto &seg : segments)
668 {
669 if (seg.is_error ())
670 {
671 rust_debug (
672 "when parsing simple path, somehow empty path segment was "
673 "not filtered out. Path begins with '%s'",
674 segments.at (0).as_string ().c_str ());
675 }
676 }
677
678 return AST::SimplePath (std::move (segments), has_opening_scope_resolution,
679 locus);
680 /* TODO: now that is_simple_path_segment exists, could probably start
681 * actually making errors upon parse failure of segments and whatever */
682}
683
684/* Parses a single SimplePathSegment (does not handle the scope resolution
685 * operators) */
686template <typename ManagedTokenSource>
687AST::SimplePathSegment
688Parser<ManagedTokenSource>::parse_simple_path_segment ()
689{
b5265142 690 using namespace Values;
35e4f3b4
JP
691 const_TokenPtr t = lexer.peek_token ();
692 switch (t->get_id ())
693 {
694 case IDENTIFIER:
695 lexer.skip_token ();
696
697 return AST::SimplePathSegment (t->get_str (), t->get_locus ());
698 case SUPER:
699 lexer.skip_token ();
700
b5265142 701 return AST::SimplePathSegment (Keywords::SUPER, t->get_locus ());
35e4f3b4
JP
702 case SELF:
703 lexer.skip_token ();
704
b5265142 705 return AST::SimplePathSegment (Keywords::SELF, t->get_locus ());
35e4f3b4
JP
706 case CRATE:
707 lexer.skip_token ();
708
b5265142 709 return AST::SimplePathSegment (Keywords::CRATE, t->get_locus ());
35e4f3b4
JP
710 case DOLLAR_SIGN:
711 if (lexer.peek_token (1)->get_id () == CRATE)
712 {
713 lexer.skip_token (1);
714
715 return AST::SimplePathSegment ("$crate", t->get_locus ());
716 }
717 gcc_fallthrough ();
718 default:
719 // do nothing but inactivates warning from gcc when compiling
720 /* could put the rust_error_at thing here but fallthrough (from failing
721 * $crate condition) isn't completely obvious if it is. */
722
723 // test prevent error
724 return AST::SimplePathSegment::create_error ();
725 }
93866b6a 726 rust_unreachable ();
35e4f3b4
JP
727 /*rust_error_at(
728 t->get_locus(), "invalid token '%s' in simple path segment",
729 t->get_token_description());*/
730 // this is not necessarily an error, e.g. end of path
731 // return AST::SimplePathSegment::create_error();
732}
733
734// Parses a PathIdentSegment - an identifier segment of a non-SimplePath path.
735template <typename ManagedTokenSource>
736AST::PathIdentSegment
737Parser<ManagedTokenSource>::parse_path_ident_segment ()
738{
739 const_TokenPtr t = lexer.peek_token ();
740 switch (t->get_id ())
741 {
742 case IDENTIFIER:
743 lexer.skip_token ();
744
745 return AST::PathIdentSegment (t->get_str (), t->get_locus ());
746 case SUPER:
747 lexer.skip_token ();
748
f1c7ce7e 749 return AST::PathIdentSegment (Values::Keywords::SUPER, t->get_locus ());
35e4f3b4
JP
750 case SELF:
751 lexer.skip_token ();
752
f1c7ce7e 753 return AST::PathIdentSegment (Values::Keywords::SELF, t->get_locus ());
35e4f3b4
JP
754 case SELF_ALIAS:
755 lexer.skip_token ();
756
f1c7ce7e
PEP
757 return AST::PathIdentSegment (Values::Keywords::SELF_ALIAS,
758 t->get_locus ());
35e4f3b4
JP
759 case CRATE:
760 lexer.skip_token ();
761
f1c7ce7e 762 return AST::PathIdentSegment (Values::Keywords::CRATE, t->get_locus ());
35e4f3b4
JP
763 case DOLLAR_SIGN:
764 if (lexer.peek_token (1)->get_id () == CRATE)
765 {
766 lexer.skip_token (1);
767
768 return AST::PathIdentSegment ("$crate", t->get_locus ());
769 }
770 gcc_fallthrough ();
771 default:
772 /* do nothing but inactivates warning from gcc when compiling
773 * could put the error_at thing here but fallthrough (from failing $crate
774 * condition) isn't completely obvious if it is. */
775
776 // test prevent error
777 return AST::PathIdentSegment::create_error ();
778 }
93866b6a 779 rust_unreachable ();
35e4f3b4
JP
780 // not necessarily an error
781}
782
783// Parses an AttrInput AST node (polymorphic, as AttrInput is abstract)
784template <typename ManagedTokenSource>
785std::unique_ptr<AST::AttrInput>
786Parser<ManagedTokenSource>::parse_attr_input ()
787{
788 const_TokenPtr t = lexer.peek_token ();
789 switch (t->get_id ())
790 {
791 case LEFT_PAREN:
792 case LEFT_SQUARE:
793 case LEFT_CURLY: {
794 // must be a delimited token tree, so parse that
795 std::unique_ptr<AST::AttrInput> input_tree (
796 new AST::DelimTokenTree (parse_delim_token_tree ()));
797
798 // TODO: potential checks on DelimTokenTree before returning
799
800 return input_tree;
801 }
802 case EQUAL: {
803 // = LiteralExpr
804 lexer.skip_token ();
805
806 t = lexer.peek_token ();
807
efc6c1aa
OA
808 // attempt to parse macro
809 // TODO: macros may/may not be allowed in attributes
810 // this is needed for "#[doc = include_str!(...)]"
811 if (is_simple_path_segment (t->get_id ()))
812 {
813 std::unique_ptr<AST::MacroInvocation> invoke
814 = parse_macro_invocation ({});
815
816 if (!invoke)
817 return nullptr;
818
819 return std::unique_ptr<AST::AttrInput> (
820 new AST::AttrInputMacro (std::move (invoke)));
821 }
822
35e4f3b4
JP
823 /* Ensure token is a "literal expression" (literally only a literal
824 * token of any type) */
825 if (!t->is_literal ())
826 {
827 Error error (
828 t->get_locus (),
829 "unknown token %qs in attribute body - literal expected",
830 t->get_token_description ());
831 add_error (std::move (error));
832
833 skip_after_end_attribute ();
834 return nullptr;
835 }
836
837 AST::Literal::LitType lit_type = AST::Literal::STRING;
838 // Crappy mapping of token type to literal type
839 switch (t->get_id ())
840 {
841 case INT_LITERAL:
842 lit_type = AST::Literal::INT;
843 break;
844 case FLOAT_LITERAL:
845 lit_type = AST::Literal::FLOAT;
846 break;
847 case CHAR_LITERAL:
848 lit_type = AST::Literal::CHAR;
849 break;
850 case BYTE_CHAR_LITERAL:
851 lit_type = AST::Literal::BYTE;
852 break;
853 case BYTE_STRING_LITERAL:
854 lit_type = AST::Literal::BYTE_STRING;
855 break;
908a4f88 856 case RAW_STRING_LITERAL:
857 lit_type = AST::Literal::RAW_STRING;
858 break;
35e4f3b4
JP
859 case STRING_LITERAL:
860 default:
861 lit_type = AST::Literal::STRING;
862 break; // TODO: raw string? don't eliminate it from lexer?
863 }
864
865 // create actual LiteralExpr
866 AST::LiteralExpr lit_expr (t->get_str (), lit_type, t->get_type_hint (),
867 {}, t->get_locus ());
868 lexer.skip_token ();
869
870 std::unique_ptr<AST::AttrInput> attr_input_lit (
871 new AST::AttrInputLiteral (std::move (lit_expr)));
872
873 // do checks or whatever? none required, really
874
875 // FIXME: shouldn't a skip token be required here?
876
877 return attr_input_lit;
878 }
879 break;
880 case RIGHT_SQUARE:
881 // means AttrInput is missing, which is allowed
882 return nullptr;
883 default:
884 add_error (
885 Error (t->get_locus (),
886 "unknown token %qs in attribute body - attribute input or "
887 "none expected",
888 t->get_token_description ()));
889
890 skip_after_end_attribute ();
891 return nullptr;
892 }
93866b6a 893 rust_unreachable ();
35e4f3b4
JP
894 // TODO: find out how to stop gcc error on "no return value"
895}
896
897/* Returns true if the token id matches the delimiter type. Note that this only
898 * operates for END delimiter tokens. */
899inline bool
900token_id_matches_delims (TokenId token_id, AST::DelimType delim_type)
901{
902 return ((token_id == RIGHT_PAREN && delim_type == AST::PARENS)
903 || (token_id == RIGHT_SQUARE && delim_type == AST::SQUARE)
904 || (token_id == RIGHT_CURLY && delim_type == AST::CURLY));
905}
906
907/* Returns true if the likely result of parsing the next few tokens is a path.
908 * Not guaranteed, though, especially in the case of syntax errors. */
909inline bool
910is_likely_path_next (TokenId next_token_id)
911{
912 switch (next_token_id)
913 {
914 case IDENTIFIER:
915 case SUPER:
916 case SELF:
917 case SELF_ALIAS:
918 case CRATE:
919 // maybe - maybe do extra check. But then requires another TokenId.
920 case DOLLAR_SIGN:
921 case SCOPE_RESOLUTION:
922 return true;
923 default:
924 return false;
925 }
926}
927
928// Parses a delimited token tree
929template <typename ManagedTokenSource>
930AST::DelimTokenTree
931Parser<ManagedTokenSource>::parse_delim_token_tree ()
932{
933 const_TokenPtr t = lexer.peek_token ();
934 lexer.skip_token ();
80c68893 935 location_t initial_loc = t->get_locus ();
35e4f3b4
JP
936
937 // save delim type to ensure it is reused later
938 AST::DelimType delim_type = AST::PARENS;
939
940 // Map tokens to DelimType
941 switch (t->get_id ())
942 {
943 case LEFT_PAREN:
944 delim_type = AST::PARENS;
945 break;
946 case LEFT_SQUARE:
947 delim_type = AST::SQUARE;
948 break;
949 case LEFT_CURLY:
950 delim_type = AST::CURLY;
951 break;
952 default:
953 add_error (Error (t->get_locus (),
954 "unexpected token %qs - expecting delimiters (for a "
955 "delimited token tree)",
956 t->get_token_description ()));
957
958 return AST::DelimTokenTree::create_empty ();
959 }
960
961 // parse actual token tree vector - 0 or more
962 std::vector<std::unique_ptr<AST::TokenTree>> token_trees_in_tree;
963 auto delim_open
964 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
965 token_trees_in_tree.push_back (std::move (delim_open));
966
967 // repeat loop until finding the matching delimiter
968 t = lexer.peek_token ();
969 while (!token_id_matches_delims (t->get_id (), delim_type)
970 && t->get_id () != END_OF_FILE)
971 {
972 std::unique_ptr<AST::TokenTree> tok_tree = parse_token_tree ();
973
974 if (tok_tree == nullptr)
975 {
976 // TODO: is this error handling appropriate?
977 Error error (
978 t->get_locus (),
979 "failed to parse token tree in delimited token tree - found %qs",
980 t->get_token_description ());
981 add_error (std::move (error));
982
983 return AST::DelimTokenTree::create_empty ();
984 }
985
986 token_trees_in_tree.push_back (std::move (tok_tree));
987
988 // lexer.skip_token();
989 t = lexer.peek_token ();
990 }
991 auto delim_close
992 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
993 token_trees_in_tree.push_back (std::move (delim_close));
994
995 AST::DelimTokenTree token_tree (delim_type, std::move (token_trees_in_tree),
996 initial_loc);
997
998 // parse end delimiters
999 t = lexer.peek_token ();
1000
1001 if (token_id_matches_delims (t->get_id (), delim_type))
1002 {
1003 // tokens match opening delimiter, so skip.
1004 lexer.skip_token ();
1005
1006 // DEBUG
1007 rust_debug ("finished parsing new delim token tree - peeked token is now "
1008 "'%s' while t is '%s'",
1009 lexer.peek_token ()->get_token_description (),
1010 t->get_token_description ());
1011
1012 return token_tree;
1013 }
1014 else
1015 {
1016 // tokens don't match opening delimiters, so produce error
1017 Error error (t->get_locus (),
1018 "unexpected token %qs - expecting closing delimiter %qs "
1019 "(for a delimited token tree)",
1020 t->get_token_description (),
1021 (delim_type == AST::PARENS
1022 ? ")"
1023 : (delim_type == AST::SQUARE ? "]" : "}")));
1024 add_error (std::move (error));
1025
1026 /* return empty token tree despite possibly parsing valid token tree -
1027 * TODO is this a good idea? */
1028 return AST::DelimTokenTree::create_empty ();
1029 }
1030}
1031
2aeff9ce
OA
1032// Parses an identifier/keyword as a Token
1033template <typename ManagedTokenSource>
1034std::unique_ptr<AST::Token>
1035Parser<ManagedTokenSource>::parse_identifier_or_keyword_token ()
1036{
1037 const_TokenPtr t = lexer.peek_token ();
1038
1039 if (t->get_id () == IDENTIFIER || token_id_is_keyword (t->get_id ()))
1040 {
1041 lexer.skip_token ();
1042 return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1043 }
1044 else
1045 {
1046 return nullptr;
1047 }
1048}
1049
35e4f3b4
JP
1050/* Parses a TokenTree syntactical production. This is either a delimited token
1051 * tree or a non-delimiter token. */
1052template <typename ManagedTokenSource>
1053std::unique_ptr<AST::TokenTree>
1054Parser<ManagedTokenSource>::parse_token_tree ()
1055{
1056 const_TokenPtr t = lexer.peek_token ();
1057
1058 switch (t->get_id ())
1059 {
1060 case LEFT_PAREN:
1061 case LEFT_SQUARE:
1062 case LEFT_CURLY:
1063 // Parse delimited token tree
1064 // TODO: use move rather than copy constructor
1065 return std::unique_ptr<AST::DelimTokenTree> (
1066 new AST::DelimTokenTree (parse_delim_token_tree ()));
1067 case RIGHT_PAREN:
1068 case RIGHT_SQUARE:
1069 case RIGHT_CURLY:
1070 // error - should not be called when this a token
1071 add_error (
1072 Error (t->get_locus (),
1073 "unexpected closing delimiter %qs - token tree requires "
1074 "either paired delimiters or non-delimiter tokens",
1075 t->get_token_description ()));
1076
1077 lexer.skip_token ();
1078 return nullptr;
1079 default:
1080 // parse token itself as TokenTree
1081 lexer.skip_token ();
1082 return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1083 }
1084}
1085
68a8a550
PEP
1086template <typename ManagedTokenSource>
1087bool
1088Parser<ManagedTokenSource>::is_macro_rules_def (const_TokenPtr t)
1089{
1090 auto macro_name = lexer.peek_token (2)->get_id ();
1091
1092 bool allowed_macro_name = (macro_name == IDENTIFIER || macro_name == TRY);
1093
28652f21 1094 return t->get_str () == Values::WeakKeywords::MACRO_RULES
68a8a550
PEP
1095 && lexer.peek_token (1)->get_id () == EXCLAM && allowed_macro_name;
1096}
1097
35e4f3b4
JP
1098// Parses a single item
1099template <typename ManagedTokenSource>
1100std::unique_ptr<AST::Item>
1101Parser<ManagedTokenSource>::parse_item (bool called_from_statement)
1102{
1103 // has a "called_from_statement" parameter for better error message handling
1104
1105 // parse outer attributes for item
1106 AST::AttrVec outer_attrs = parse_outer_attributes ();
35e4f3b4
JP
1107 const_TokenPtr t = lexer.peek_token ();
1108
1109 switch (t->get_id ())
1110 {
1111 case END_OF_FILE:
1112 // not necessarily an error, unless we just read outer
1113 // attributes which needs to be attached
1114 if (!outer_attrs.empty ())
1115 {
1116 Rust::AST::Attribute attr = outer_attrs.back ();
1117 Error error (attr.get_locus (),
1118 "expected item after outer attribute or doc comment");
1119 add_error (std::move (error));
1120 }
1121 return nullptr;
d5c58239
MK
1122
1123 case ASYNC:
35e4f3b4
JP
1124 case PUB:
1125 case MOD:
7f631967 1126 case EXTERN_KW:
35e4f3b4 1127 case USE:
7f631967 1128 case FN_KW:
35e4f3b4 1129 case TYPE:
7f631967
PEP
1130 case STRUCT_KW:
1131 case ENUM_KW:
35e4f3b4 1132 case CONST:
7f631967 1133 case STATIC_KW:
22128105 1134 case AUTO:
35e4f3b4
JP
1135 case TRAIT:
1136 case IMPL:
e1394230 1137 case MACRO:
35e4f3b4
JP
1138 /* TODO: implement union keyword but not really because of
1139 * context-dependence crappy hack way to parse a union written below to
1140 * separate it from the good code. */
1141 // case UNION:
1142 case UNSAFE: // maybe - unsafe traits are a thing
1143 // if any of these (should be all possible VisItem prefixes), parse a
1144 // VisItem
1145 return parse_vis_item (std::move (outer_attrs));
1146 break;
1147 case SUPER:
1148 case SELF:
1149 case CRATE:
1150 case DOLLAR_SIGN:
1151 // almost certainly macro invocation semi
e1394230 1152 return parse_macro_invocation_semi (std::move (outer_attrs));
35e4f3b4
JP
1153 break;
1154 // crappy hack to do union "keyword"
1155 case IDENTIFIER:
1156 // TODO: ensure std::string and literal comparison works
28652f21 1157 if (t->get_str () == Values::WeakKeywords::UNION
35e4f3b4
JP
1158 && lexer.peek_token (1)->get_id () == IDENTIFIER)
1159 {
1160 return parse_vis_item (std::move (outer_attrs));
1161 // or should this go straight to parsing union?
1162 }
28652f21 1163 else if (t->get_str () == Values::WeakKeywords::DEFAULT
1e039d2f 1164 && lexer.peek_token (1)->get_id () != EXCLAM)
73b6d9b9
AC
1165 {
1166 add_error (Error (t->get_locus (),
1167 "%qs is only allowed on items within %qs blocks",
1168 "default", "impl"));
1169 return nullptr;
1170 }
68a8a550 1171 else if (is_macro_rules_def (t))
35e4f3b4
JP
1172 {
1173 // macro_rules! macro item
e1394230 1174 return parse_macro_rules_def (std::move (outer_attrs));
35e4f3b4
JP
1175 }
1176 else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
1177 || lexer.peek_token (1)->get_id () == EXCLAM)
1178 {
1179 /* path (probably) or macro invocation, so probably a macro invocation
1180 * semi */
e1394230 1181 return parse_macro_invocation_semi (std::move (outer_attrs));
35e4f3b4
JP
1182 }
1183 gcc_fallthrough ();
1184 default:
1185 // otherwise unrecognised
35e4f3b4
JP
1186 add_error (Error (t->get_locus (),
1187 "unrecognised token %qs for start of %s",
1188 t->get_token_description (),
1189 called_from_statement ? "statement" : "item"));
1190
1191 // skip somewhere?
1192 return nullptr;
1193 break;
1194 }
1195}
1196
1197// Parses a contiguous block of outer attributes.
1198template <typename ManagedTokenSource>
1199AST::AttrVec
1200Parser<ManagedTokenSource>::parse_outer_attributes ()
1201{
1202 AST::AttrVec outer_attributes;
1203
1204 while (lexer.peek_token ()->get_id ()
1205 == HASH /* Can also be #!, which catches errors. */
1206 || lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT
1207 || lexer.peek_token ()->get_id ()
1208 == INNER_DOC_COMMENT) /* For error handling. */
1209 {
1210 AST::Attribute outer_attr = parse_outer_attribute ();
1211
1212 /* Ensure only valid outer attributes are added to the outer_attributes
1213 * list */
1214 if (!outer_attr.is_empty ())
1215 {
1216 outer_attributes.push_back (std::move (outer_attr));
1217 }
1218 else
1219 {
1220 /* If no more valid outer attributes, break out of loop (only
1221 * contiguous outer attributes parsed). */
1222 break;
1223 }
1224 }
1225
1226 outer_attributes.shrink_to_fit ();
1227 return outer_attributes;
1228
1229 /* TODO: this shares basically all code with parse_inner_attributes except
1230 * function call - find way of making it more modular? function pointer? */
1231}
1232
1233// Parse a single outer attribute.
1234template <typename ManagedTokenSource>
1235AST::Attribute
1236Parser<ManagedTokenSource>::parse_outer_attribute ()
1237{
1238 if (lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT)
9a7a79eb
PEP
1239 {
1240 auto values = parse_doc_comment ();
1241 auto path = std::move (std::get<0> (values));
1242 auto input = std::move (std::get<1> (values));
1243 auto loc = std::get<2> (values);
1244 return AST::Attribute (std::move (path), std::move (input), loc, false);
1245 }
35e4f3b4
JP
1246
1247 if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
1248 {
1249 Error error (
c0b25c9a
MM
1250 lexer.peek_token ()->get_locus (), ErrorCode::E0753,
1251 "expected outer doc comment, inner doc (%<//!%> or %</*!%>) only "
1252 "allowed at start of item "
35e4f3b4
JP
1253 "and before any outer attribute or doc (%<#[%>, %<///%> or %</**%>)");
1254 add_error (std::move (error));
1255 lexer.skip_token ();
1256 return AST::Attribute::create_empty ();
1257 }
1258
1259 /* OuterAttribute -> '#' '[' Attr ']' */
1260
1261 if (lexer.peek_token ()->get_id () != HASH)
1262 return AST::Attribute::create_empty ();
1263
1264 lexer.skip_token ();
1265
1266 TokenId id = lexer.peek_token ()->get_id ();
1267 if (id != LEFT_SQUARE)
1268 {
1269 if (id == EXCLAM)
1270 {
1271 // this is inner attribute syntax, so throw error
1272 // inner attributes were either already parsed or not allowed here.
1273 Error error (
1274 lexer.peek_token ()->get_locus (),
1275 "token %<!%> found, indicating inner attribute definition. Inner "
1276 "attributes are not possible at this location");
1277 add_error (std::move (error));
1278 }
1279 return AST::Attribute::create_empty ();
1280 }
1281
1282 lexer.skip_token ();
1283
9a7a79eb
PEP
1284 auto values = parse_attribute_body ();
1285 auto path = std::move (std::get<0> (values));
1286 auto input = std::move (std::get<1> (values));
1287 auto loc = std::get<2> (values);
1288 auto actual_attribute
9113e076 1289 = AST::Attribute (std::move (path), std::move (input), loc, false);
35e4f3b4
JP
1290
1291 if (lexer.peek_token ()->get_id () != RIGHT_SQUARE)
1292 return AST::Attribute::create_empty ();
1293
1294 lexer.skip_token ();
1295
1296 return actual_attribute;
1297}
1298
1299// Parses a VisItem (item that can have non-default visibility).
1300template <typename ManagedTokenSource>
1301std::unique_ptr<AST::VisItem>
1302Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
1303{
1304 // parse visibility, which may or may not exist
1305 AST::Visibility vis = parse_visibility ();
1306
1307 // select VisItem to create depending on keyword
1308 const_TokenPtr t = lexer.peek_token ();
1309
1310 switch (t->get_id ())
1311 {
1312 case MOD:
1313 return parse_module (std::move (vis), std::move (outer_attrs));
7f631967 1314 case EXTERN_KW:
35e4f3b4
JP
1315 // lookahead to resolve syntactical production
1316 t = lexer.peek_token (1);
1317
1318 switch (t->get_id ())
1319 {
1320 case CRATE:
1321 return parse_extern_crate (std::move (vis), std::move (outer_attrs));
7f631967 1322 case FN_KW: // extern function
35e4f3b4
JP
1323 return parse_function (std::move (vis), std::move (outer_attrs));
1324 case LEFT_CURLY: // extern block
1325 return parse_extern_block (std::move (vis), std::move (outer_attrs));
1326 case STRING_LITERAL: // for specifying extern ABI
1327 // could be extern block or extern function, so more lookahead
1328 t = lexer.peek_token (2);
1329
1330 switch (t->get_id ())
1331 {
7f631967 1332 case FN_KW:
35e4f3b4
JP
1333 return parse_function (std::move (vis), std::move (outer_attrs));
1334 case LEFT_CURLY:
1335 return parse_extern_block (std::move (vis),
1336 std::move (outer_attrs));
1337 default:
1338 add_error (
1339 Error (t->get_locus (),
1340 "unexpected token %qs in some sort of extern production",
1341 t->get_token_description ()));
1342
1343 lexer.skip_token (2); // TODO: is this right thing to do?
1344 return nullptr;
1345 }
1346 default:
1347 add_error (
1348 Error (t->get_locus (),
1349 "unexpected token %qs in some sort of extern production",
1350 t->get_token_description ()));
1351
1352 lexer.skip_token (1); // TODO: is this right thing to do?
1353 return nullptr;
1354 }
1355 case USE:
1356 return parse_use_decl (std::move (vis), std::move (outer_attrs));
7f631967 1357 case FN_KW:
35e4f3b4
JP
1358 return parse_function (std::move (vis), std::move (outer_attrs));
1359 case TYPE:
1360 return parse_type_alias (std::move (vis), std::move (outer_attrs));
7f631967 1361 case STRUCT_KW:
35e4f3b4 1362 return parse_struct (std::move (vis), std::move (outer_attrs));
7f631967 1363 case ENUM_KW:
35e4f3b4
JP
1364 return parse_enum (std::move (vis), std::move (outer_attrs));
1365 // TODO: implement union keyword but not really because of
1366 // context-dependence case UNION: crappy hack to do union "keyword"
1367 case IDENTIFIER:
28652f21 1368 if (t->get_str () == Values::WeakKeywords::UNION
35e4f3b4
JP
1369 && lexer.peek_token (1)->get_id () == IDENTIFIER)
1370 {
1371 return parse_union (std::move (vis), std::move (outer_attrs));
1372 // or should item switch go straight to parsing union?
1373 }
1374 else
1375 {
1376 break;
1377 }
1378 case CONST:
1379 // lookahead to resolve syntactical production
1380 t = lexer.peek_token (1);
1381
1382 switch (t->get_id ())
1383 {
1384 case IDENTIFIER:
1385 case UNDERSCORE:
1386 return parse_const_item (std::move (vis), std::move (outer_attrs));
68990dbe
PEP
1387 case ASYNC:
1388 return parse_async_item (std::move (vis), std::move (outer_attrs));
d3acfa7c
OA
1389 case UNSAFE:
1390 case EXTERN_KW:
7f631967 1391 case FN_KW:
35e4f3b4
JP
1392 return parse_function (std::move (vis), std::move (outer_attrs));
1393 default:
1394 add_error (
1395 Error (t->get_locus (),
1396 "unexpected token %qs in some sort of const production",
1397 t->get_token_description ()));
1398
1399 lexer.skip_token (1); // TODO: is this right thing to do?
1400 return nullptr;
1401 }
d5c58239
MK
1402 // for async functions
1403 case ASYNC:
1404 return parse_async_item (std::move (vis), std::move (outer_attrs));
1405
7f631967 1406 case STATIC_KW:
35e4f3b4 1407 return parse_static_item (std::move (vis), std::move (outer_attrs));
22128105 1408 case AUTO:
35e4f3b4
JP
1409 case TRAIT:
1410 return parse_trait (std::move (vis), std::move (outer_attrs));
1411 case IMPL:
1412 return parse_impl (std::move (vis), std::move (outer_attrs));
1413 case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls),
1414 // lookahead to resolve syntactical production
1415 t = lexer.peek_token (1);
1416
1417 switch (t->get_id ())
1418 {
22128105 1419 case AUTO:
35e4f3b4
JP
1420 case TRAIT:
1421 return parse_trait (std::move (vis), std::move (outer_attrs));
7f631967
PEP
1422 case EXTERN_KW:
1423 case FN_KW:
35e4f3b4
JP
1424 return parse_function (std::move (vis), std::move (outer_attrs));
1425 case IMPL:
1426 return parse_impl (std::move (vis), std::move (outer_attrs));
d6a0d965
PEP
1427 case MOD:
1428 return parse_module (std::move (vis), std::move (outer_attrs));
35e4f3b4
JP
1429 default:
1430 add_error (
1431 Error (t->get_locus (),
1432 "unexpected token %qs in some sort of unsafe production",
1433 t->get_token_description ()));
1434
1435 lexer.skip_token (1); // TODO: is this right thing to do?
1436 return nullptr;
1437 }
e1394230
RT
1438 case MACRO:
1439 return parse_decl_macro_def (std::move (vis), std::move (outer_attrs));
35e4f3b4
JP
1440 default:
1441 // otherwise vis item clearly doesn't exist, which is not an error
1442 // has a catch-all post-switch return to allow other breaks to occur
1443 break;
1444 }
1445 return nullptr;
1446}
1447
d5c58239
MK
1448template <typename ManagedTokenSource>
1449std::unique_ptr<AST::Function>
1450Parser<ManagedTokenSource>::parse_async_item (AST::Visibility vis,
1451 AST::AttrVec outer_attrs)
1452{
68990dbe
PEP
1453 auto offset = (lexer.peek_token ()->get_id () == CONST) ? 1 : 0;
1454 const_TokenPtr t = lexer.peek_token (offset);
1455
e06530a5 1456 if (get_rust_edition () == Edition::E2015)
d5c58239
MK
1457 {
1458 add_error (Error (t->get_locus (), ErrorCode::E0670,
1459 "%<async fn%> is not permitted in Rust 2015"));
1460 add_error (
1461 Error::Hint (t->get_locus (),
1462 "to use %<async fn%>, switch to Rust 2018 or later"));
1463 }
1464
68990dbe 1465 t = lexer.peek_token (offset + 1);
d5c58239
MK
1466
1467 switch (t->get_id ())
1468 {
1469 case UNSAFE:
1470 case FN_KW:
1471 return parse_function (std::move (vis), std::move (outer_attrs));
1472
1473 default:
1474 add_error (
1475 Error (t->get_locus (), "expected item, found keyword %<async%>"));
1476
1477 lexer.skip_token (1);
1478 return nullptr;
1479 }
1480}
1481
35e4f3b4
JP
1482// Parses a macro rules definition syntax extension whatever thing.
1483template <typename ManagedTokenSource>
1484std::unique_ptr<AST::MacroRulesDefinition>
1485Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
1486{
1487 // ensure that first token is identifier saying "macro_rules"
1488 const_TokenPtr t = lexer.peek_token ();
28652f21
PEP
1489 if (t->get_id () != IDENTIFIER
1490 || t->get_str () != Values::WeakKeywords::MACRO_RULES)
35e4f3b4
JP
1491 {
1492 Error error (
1493 t->get_locus (),
1494 "macro rules definition does not start with %<macro_rules%>");
1495 add_error (std::move (error));
1496
1497 // skip after somewhere?
1498 return nullptr;
1499 }
1500 lexer.skip_token ();
80c68893 1501 location_t macro_locus = t->get_locus ();
35e4f3b4
JP
1502
1503 if (!skip_token (EXCLAM))
1504 {
1505 // skip after somewhere?
1506 return nullptr;
1507 }
1508
1509 // parse macro name
1510 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
1511 if (ident_tok == nullptr)
1512 {
1513 return nullptr;
1514 }
1c3a8fbb 1515 Identifier rule_name{ident_tok};
35e4f3b4
JP
1516
1517 // DEBUG
1518 rust_debug ("in macro rules def, about to parse parens.");
1519
1520 // save delim type to ensure it is reused later
1521 AST::DelimType delim_type = AST::PARENS;
1522
1523 // Map tokens to DelimType
1524 t = lexer.peek_token ();
1525 switch (t->get_id ())
1526 {
1527 case LEFT_PAREN:
1528 delim_type = AST::PARENS;
1529 break;
1530 case LEFT_SQUARE:
1531 delim_type = AST::SQUARE;
1532 break;
1533 case LEFT_CURLY:
1534 delim_type = AST::CURLY;
1535 break;
1536 default:
1537 add_error (Error (t->get_locus (),
1538 "unexpected token %qs - expecting delimiters (for a "
1539 "macro rules definition)",
1540 t->get_token_description ()));
1541
1542 return nullptr;
1543 }
1544 lexer.skip_token ();
1545
1546 // parse actual macro rules
1547 std::vector<AST::MacroRule> macro_rules;
1548
1549 // must be at least one macro rule, so parse it
1550 AST::MacroRule initial_rule = parse_macro_rule ();
1551 if (initial_rule.is_error ())
1552 {
1553 Error error (lexer.peek_token ()->get_locus (),
1554 "required first macro rule in macro rules definition "
1555 "could not be parsed");
1556 add_error (std::move (error));
1557
1558 // skip after somewhere?
1559 return nullptr;
1560 }
1561 macro_rules.push_back (std::move (initial_rule));
1562
1563 // DEBUG
1564 rust_debug ("successfully pushed back initial macro rule");
1565
1566 t = lexer.peek_token ();
1567 // parse macro rules
1568 while (t->get_id () == SEMICOLON)
1569 {
1570 // skip semicolon
1571 lexer.skip_token ();
1572
1573 // don't parse if end of macro rules
1574 if (token_id_matches_delims (lexer.peek_token ()->get_id (), delim_type))
1575 {
1576 // DEBUG
1577 rust_debug (
1578 "broke out of parsing macro rules loop due to finding delim");
1579
1580 break;
1581 }
1582
1583 // try to parse next rule
1584 AST::MacroRule rule = parse_macro_rule ();
1585 if (rule.is_error ())
1586 {
1587 Error error (lexer.peek_token ()->get_locus (),
1588 "failed to parse macro rule in macro rules definition");
1589 add_error (std::move (error));
1590
1591 return nullptr;
1592 }
1593
1594 macro_rules.push_back (std::move (rule));
1595
1596 // DEBUG
1597 rust_debug ("successfully pushed back another macro rule");
1598
1599 t = lexer.peek_token ();
1600 }
1601
1602 // parse end delimiters
1603 t = lexer.peek_token ();
1604 if (token_id_matches_delims (t->get_id (), delim_type))
1605 {
1606 // tokens match opening delimiter, so skip.
1607 lexer.skip_token ();
1608
1609 if (delim_type != AST::CURLY)
1610 {
1611 // skip semicolon at end of non-curly macro definitions
1612 if (!skip_token (SEMICOLON))
1613 {
1614 // as this is the end, allow recovery (probably) - may change
1615 return std::unique_ptr<AST::MacroRulesDefinition> (
e1394230 1616 AST::MacroRulesDefinition::mbe (
35e4f3b4
JP
1617 std::move (rule_name), delim_type, std::move (macro_rules),
1618 std::move (outer_attrs), macro_locus));
1619 }
1620 }
1621
1622 return std::unique_ptr<AST::MacroRulesDefinition> (
e1394230
RT
1623 AST::MacroRulesDefinition::mbe (std::move (rule_name), delim_type,
1624 std::move (macro_rules),
1625 std::move (outer_attrs), macro_locus));
35e4f3b4
JP
1626 }
1627 else
1628 {
1629 // tokens don't match opening delimiters, so produce error
1630 Error error (t->get_locus (),
1631 "unexpected token %qs - expecting closing delimiter %qs "
1632 "(for a macro rules definition)",
1633 t->get_token_description (),
1634 (delim_type == AST::PARENS
1635 ? ")"
1636 : (delim_type == AST::SQUARE ? "]" : "}")));
1637 add_error (std::move (error));
1638
1639 /* return empty macro definiton despite possibly parsing mostly valid one
1640 * - TODO is this a good idea? */
1641 return nullptr;
1642 }
1643}
1644
e1394230
RT
1645// Parses a declarative macro 2.0 definition.
1646template <typename ManagedTokenSource>
1647std::unique_ptr<AST::MacroRulesDefinition>
1648Parser<ManagedTokenSource>::parse_decl_macro_def (AST::Visibility vis,
1649 AST::AttrVec outer_attrs)
1650{
1651 // ensure that first token is identifier saying "macro"
1652 const_TokenPtr t = lexer.peek_token ();
1653 if (t->get_id () != MACRO)
1654 {
1655 Error error (
1656 t->get_locus (),
1657 "declarative macro definition does not start with %<macro%>");
1658 add_error (std::move (error));
1659
1660 // skip after somewhere?
1661 return nullptr;
1662 }
1663 lexer.skip_token ();
80c68893 1664 location_t macro_locus = t->get_locus ();
e1394230
RT
1665
1666 // parse macro name
1667 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
1668 if (ident_tok == nullptr)
1669 {
1670 return nullptr;
1671 }
1c3a8fbb 1672 Identifier rule_name{ident_tok};
e1394230
RT
1673
1674 t = lexer.peek_token ();
1675 if (t->get_id () == LEFT_PAREN)
1676 {
1677 // single definiton of macro rule
1678 // e.g. `macro foo($e:expr) {}`
1679
1680 // parse macro matcher
d991a3f1 1681 location_t locus = lexer.peek_token ()->get_locus ();
e1394230
RT
1682 AST::MacroMatcher matcher = parse_macro_matcher ();
1683 if (matcher.is_error ())
1684 return nullptr;
1685
1686 // check delimiter of macro matcher
1687 if (matcher.get_delim_type () != AST::DelimType::PARENS)
1688 {
1689 Error error (locus, "only parenthesis can be used for a macro "
1690 "matcher in declarative macro definition");
1691 add_error (std::move (error));
1692 return nullptr;
1693 }
1694
80c68893 1695 location_t transcriber_loc = lexer.peek_token ()->get_locus ();
e1394230
RT
1696 AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree ();
1697 AST::MacroTranscriber transcriber (delim_tok_tree, transcriber_loc);
1698
1699 if (transcriber.get_token_tree ().get_delim_type ()
1700 != AST::DelimType::CURLY)
1701 {
1702 Error error (transcriber_loc,
1703 "only braces can be used for a macro transcriber "
1704 "in declarative macro definition");
1705 add_error (std::move (error));
1706 return nullptr;
1707 }
1708
1709 AST::MacroRule macro_rule
1710 = AST::MacroRule (std::move (matcher), std::move (transcriber), locus);
1711 std::vector<AST::MacroRule> macro_rules;
1712 macro_rules.push_back (macro_rule);
1713
1714 return std::unique_ptr<AST::MacroRulesDefinition> (
1715 AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
1716 macro_rules,
1717 std::move (outer_attrs),
1718 macro_locus, vis));
1719 }
1720 else if (t->get_id () == LEFT_CURLY)
1721 {
1722 // multiple definitions of macro rule separated by comma
1723 // e.g. `macro foo { () => {}, ($e:expr) => {}, }`
1724
1725 // parse left curly
1726 const_TokenPtr left_curly = expect_token (LEFT_CURLY);
1727 if (left_curly == nullptr)
1728 {
1729 return nullptr;
1730 }
1731
1732 // parse actual macro rules
1733 std::vector<AST::MacroRule> macro_rules;
1734
1735 // must be at least one macro rule, so parse it
1736 AST::MacroRule initial_rule = parse_macro_rule ();
1737 if (initial_rule.is_error ())
1738 {
1739 Error error (
1740 lexer.peek_token ()->get_locus (),
1741 "required first macro rule in declarative macro definition "
1742 "could not be parsed");
1743 add_error (std::move (error));
1744
1745 // skip after somewhere?
1746 return nullptr;
1747 }
1748 macro_rules.push_back (std::move (initial_rule));
1749
1750 t = lexer.peek_token ();
1751 // parse macro rules
1752 while (t->get_id () == COMMA)
1753 {
1754 // skip comma
1755 lexer.skip_token ();
1756
1757 // don't parse if end of macro rules
1758 if (token_id_matches_delims (lexer.peek_token ()->get_id (),
1759 AST::CURLY))
1760 {
1761 break;
1762 }
1763
1764 // try to parse next rule
1765 AST::MacroRule rule = parse_macro_rule ();
1766 if (rule.is_error ())
1767 {
1768 Error error (
1769 lexer.peek_token ()->get_locus (),
1770 "failed to parse macro rule in declarative macro definition");
1771 add_error (std::move (error));
1772
1773 return nullptr;
1774 }
1775
1776 macro_rules.push_back (std::move (rule));
1777
1778 t = lexer.peek_token ();
1779 }
1780
1781 // parse right curly
1782 const_TokenPtr right_curly = expect_token (RIGHT_CURLY);
1783 if (right_curly == nullptr)
1784 {
1785 return nullptr;
1786 }
1787
1788 return std::unique_ptr<AST::MacroRulesDefinition> (
1789 AST::MacroRulesDefinition::decl_macro (std::move (rule_name),
1790 std::move (macro_rules),
1791 std::move (outer_attrs),
1792 macro_locus, vis));
1793 }
1794 else
1795 {
1796 add_error (Error (t->get_locus (),
1797 "unexpected token %qs - expecting delimiters "
1798 "(for a declarative macro definiton)",
1799 t->get_token_description ()));
1800 return nullptr;
1801 }
1802}
1803
35e4f3b4
JP
1804// Parses a semi-coloned (except for full block) macro invocation item.
1805template <typename ManagedTokenSource>
1806std::unique_ptr<AST::MacroInvocation>
1807Parser<ManagedTokenSource>::parse_macro_invocation_semi (
1808 AST::AttrVec outer_attrs)
1809{
80c68893 1810 location_t macro_locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
1811 AST::SimplePath path = parse_simple_path ();
1812
1813 if (!skip_token (EXCLAM))
1814 {
1815 // skip after somewhere?
1816 return nullptr;
1817 }
1818
1819 // save delim type to ensure it is reused later
1820 AST::DelimType delim_type = AST::PARENS;
1821
1822 // Map tokens to DelimType
1823 const_TokenPtr t = lexer.peek_token ();
1824 switch (t->get_id ())
1825 {
1826 case LEFT_PAREN:
1827 delim_type = AST::PARENS;
1828 break;
1829 case LEFT_SQUARE:
1830 delim_type = AST::SQUARE;
1831 break;
1832 case LEFT_CURLY:
1833 delim_type = AST::CURLY;
1834 break;
1835 default:
1836 add_error (Error (t->get_locus (),
1837 "unexpected token %qs - expecting delimiters (for a "
1838 "macro invocation semi body)",
1839 t->get_token_description ()));
1840
1841 return nullptr;
1842 }
80c68893 1843 location_t tok_tree_locus = t->get_locus ();
35e4f3b4
JP
1844 lexer.skip_token ();
1845
1846 // parse actual token trees
1847 std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
1848 auto delim_open
1849 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1850 token_trees.push_back (std::move (delim_open));
1851
1852 t = lexer.peek_token ();
1853 // parse token trees until the initial delimiter token is found again
1854 while (!token_id_matches_delims (t->get_id (), delim_type))
1855 {
1856 std::unique_ptr<AST::TokenTree> tree = parse_token_tree ();
1857
1858 if (tree == nullptr)
1859 {
1860 Error error (t->get_locus (),
1861 "failed to parse token tree for macro invocation semi "
1862 "- found %qs",
1863 t->get_token_description ());
1864 add_error (std::move (error));
1865
1866 return nullptr;
1867 }
1868
1869 token_trees.push_back (std::move (tree));
1870
1871 t = lexer.peek_token ();
1872 }
1873 auto delim_close
1874 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1875 token_trees.push_back (std::move (delim_close));
1876
1877 AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees),
1878 tok_tree_locus);
1879 AST::MacroInvocData invoc_data (std::move (path), std::move (delim_tok_tree));
1880
1881 // parse end delimiters
1882 t = lexer.peek_token ();
1883 if (token_id_matches_delims (t->get_id (), delim_type))
1884 {
1885 // tokens match opening delimiter, so skip.
1886 lexer.skip_token ();
1887
1888 if (delim_type != AST::CURLY)
1889 {
1890 // skip semicolon at end of non-curly macro invocation semis
1891 if (!skip_token (SEMICOLON))
1892 {
1893 // as this is the end, allow recovery (probably) - may change
1894
51b607c2
AC
1895 return AST::MacroInvocation::Regular (std::move (invoc_data),
1896 std::move (outer_attrs),
1897 macro_locus, true);
35e4f3b4
JP
1898 }
1899 }
1900
1901 // DEBUG:
1902 rust_debug ("skipped token is '%s', next token (current peek) is '%s'",
1903 t->get_token_description (),
1904 lexer.peek_token ()->get_token_description ());
1905
51b607c2
AC
1906 return AST::MacroInvocation::Regular (std::move (invoc_data),
1907 std::move (outer_attrs),
1908 macro_locus, true);
35e4f3b4
JP
1909 }
1910 else
1911 {
1912 // tokens don't match opening delimiters, so produce error
1913 Error error (t->get_locus (),
1914 "unexpected token %qs - expecting closing delimiter %qs "
1915 "(for a macro invocation semi)",
1916 t->get_token_description (),
1917 (delim_type == AST::PARENS
1918 ? ")"
1919 : (delim_type == AST::SQUARE ? "]" : "}")));
1920 add_error (std::move (error));
1921
1922 /* return empty macro invocation despite possibly parsing mostly valid one
1923 * - TODO is this a good idea? */
1924 return nullptr;
1925 }
1926}
1927
1928// Parses a non-semicoloned macro invocation (i.e. as pattern or expression).
1929template <typename ManagedTokenSource>
1930std::unique_ptr<AST::MacroInvocation>
1931Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs)
1932{
1933 // parse macro path
1934 AST::SimplePath macro_path = parse_simple_path ();
1935 if (macro_path.is_empty ())
1936 {
1937 Error error (lexer.peek_token ()->get_locus (),
1938 "failed to parse macro invocation path");
1939 add_error (std::move (error));
1940
1941 // skip?
1942 return nullptr;
1943 }
1944
1945 if (!skip_token (EXCLAM))
1946 {
1947 // skip after somewhere?
1948 return nullptr;
1949 }
1950
1951 // parse internal delim token tree
1952 AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree ();
1953
80c68893 1954 location_t macro_locus = macro_path.get_locus ();
35e4f3b4 1955
51b607c2
AC
1956 return AST::MacroInvocation::Regular (
1957 AST::MacroInvocData (std::move (macro_path), std::move (delim_tok_tree)),
1958 std::move (outer_attrs), macro_locus);
35e4f3b4
JP
1959}
1960
1961// Parses a macro rule definition - does not parse semicolons.
1962template <typename ManagedTokenSource>
1963AST::MacroRule
1964Parser<ManagedTokenSource>::parse_macro_rule ()
1965{
d991a3f1 1966 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
1967
1968 // parse macro matcher
1969 AST::MacroMatcher matcher = parse_macro_matcher ();
1970
1971 if (matcher.is_error ())
1972 return AST::MacroRule::create_error (locus);
1973
1974 if (!skip_token (MATCH_ARROW))
1975 {
1976 // skip after somewhere?
1977 return AST::MacroRule::create_error (locus);
1978 }
1979
1980 // parse transcriber (this is just a delim token tree)
80c68893 1981 location_t token_tree_loc = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
1982 AST::MacroTranscriber transcriber (parse_delim_token_tree (), token_tree_loc);
1983
1984 return AST::MacroRule (std::move (matcher), std::move (transcriber), locus);
1985}
1986
1987// Parses a macro matcher (part of a macro rule definition).
1988template <typename ManagedTokenSource>
1989AST::MacroMatcher
1990Parser<ManagedTokenSource>::parse_macro_matcher ()
1991{
1992 // save delim type to ensure it is reused later
1993 AST::DelimType delim_type = AST::PARENS;
1994
1995 // DEBUG
1996 rust_debug ("begun parsing macro matcher");
1997
1998 // Map tokens to DelimType
1999 const_TokenPtr t = lexer.peek_token ();
d991a3f1 2000 location_t locus = t->get_locus ();
35e4f3b4
JP
2001 switch (t->get_id ())
2002 {
2003 case LEFT_PAREN:
2004 delim_type = AST::PARENS;
2005 break;
2006 case LEFT_SQUARE:
2007 delim_type = AST::SQUARE;
2008 break;
2009 case LEFT_CURLY:
2010 delim_type = AST::CURLY;
2011 break;
2012 default:
2013 add_error (Error (
2014 t->get_locus (),
2015 "unexpected token %qs - expecting delimiters (for a macro matcher)",
2016 t->get_token_description ()));
2017
2018 return AST::MacroMatcher::create_error (t->get_locus ());
2019 }
2020 lexer.skip_token ();
2021
2022 // parse actual macro matches
2023 std::vector<std::unique_ptr<AST::MacroMatch>> matches;
2024 // Set of possible preceding macro matches to make sure follow-set
2025 // restrictions are respected.
2026 // TODO: Consider using std::reference_wrapper instead of raw pointers?
2027 std::vector<const AST::MacroMatch *> last_matches;
2028
2029 t = lexer.peek_token ();
2030 // parse token trees until the initial delimiter token is found again
2031 while (!token_id_matches_delims (t->get_id (), delim_type))
2032 {
2033 std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
2034
2035 if (match == nullptr)
2036 {
2037 Error error (
2038 t->get_locus (),
2039 "failed to parse macro match for macro matcher - found %qs",
2040 t->get_token_description ());
2041 add_error (std::move (error));
2042
2043 return AST::MacroMatcher::create_error (t->get_locus ());
2044 }
2045
2046 if (matches.size () > 0)
2047 {
2048 const auto *last_match = matches.back ().get ();
2049
2050 // We want to check if we are dealing with a zeroable repetition
2051 bool zeroable = false;
2052 if (last_match->get_macro_match_type ()
2053 == AST::MacroMatch::MacroMatchType::Repetition)
2054 {
2055 auto repetition
2056 = static_cast<const AST::MacroMatchRepetition *> (last_match);
2057
2058 if (repetition->get_op ()
2059 != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE)
2060 zeroable = true;
2061 }
2062
2063 if (!zeroable)
2064 last_matches.clear ();
2065
2066 last_matches.emplace_back (last_match);
2067
2068 for (auto last : last_matches)
2069 if (!is_match_compatible (*last, *match))
2070 return AST::MacroMatcher::create_error (
2071 match->get_match_locus ());
2072 }
2073
2074 matches.push_back (std::move (match));
2075
2076 // DEBUG
2077 rust_debug ("pushed back a match in macro matcher");
2078
2079 t = lexer.peek_token ();
2080 }
2081
2082 // parse end delimiters
2083 t = lexer.peek_token ();
2084 if (token_id_matches_delims (t->get_id (), delim_type))
2085 {
2086 // tokens match opening delimiter, so skip.
2087 lexer.skip_token ();
2088
2089 return AST::MacroMatcher (delim_type, std::move (matches), locus);
2090 }
2091 else
2092 {
2093 // tokens don't match opening delimiters, so produce error
2094 Error error (t->get_locus (),
2095 "unexpected token %qs - expecting closing delimiter %qs "
2096 "(for a macro matcher)",
2097 t->get_token_description (),
2098 (delim_type == AST::PARENS
2099 ? ")"
2100 : (delim_type == AST::SQUARE ? "]" : "}")));
2101 add_error (std::move (error));
2102
2103 /* return error macro matcher despite possibly parsing mostly correct one?
2104 * TODO is this the best idea? */
2105 return AST::MacroMatcher::create_error (t->get_locus ());
2106 }
2107}
2108
2109// Parses a macro match (syntax match inside a matcher in a macro rule).
2110template <typename ManagedTokenSource>
2111std::unique_ptr<AST::MacroMatch>
2112Parser<ManagedTokenSource>::parse_macro_match ()
2113{
2114 // branch based on token available
2115 const_TokenPtr t = lexer.peek_token ();
2116 switch (t->get_id ())
2117 {
2118 case LEFT_PAREN:
2119 case LEFT_SQUARE:
2120 case LEFT_CURLY: {
2121 // must be macro matcher as delimited
2122 AST::MacroMatcher matcher = parse_macro_matcher ();
2123 if (matcher.is_error ())
2124 {
2125 Error error (lexer.peek_token ()->get_locus (),
2126 "failed to parse macro matcher in macro match");
2127 add_error (std::move (error));
2128
2129 return nullptr;
2130 }
2131 return std::unique_ptr<AST::MacroMatcher> (
2132 new AST::MacroMatcher (std::move (matcher)));
2133 }
2134 case DOLLAR_SIGN: {
2135 // have to do more lookahead to determine if fragment or repetition
2136 const_TokenPtr t2 = lexer.peek_token (1);
2137 switch (t2->get_id ())
2138 {
35e4f3b4 2139 case IDENTIFIER:
cd73752a 2140 case UNDERSCORE:
35e4f3b4
JP
2141 // macro fragment
2142 return parse_macro_match_fragment ();
2143 case LEFT_PAREN:
2144 // macro repetition
2145 return parse_macro_match_repetition ();
2146 default:
d686ffaf
OA
2147 if (token_id_is_keyword (t2->get_id ()) && t2->get_id () != CRATE)
2148 {
2149 // keyword as macro fragment
2150 return parse_macro_match_fragment ();
2151 }
2152 else
2153 {
2154 // error: unrecognised
2155 add_error (Error (
2156 t2->get_locus (),
2157 "unrecognised token combination %<$%s%> at start of "
2158 "macro match - did you mean %<$identifier%> or %<$(%>?",
2159 t2->get_token_description ()));
2160
2161 // skip somewhere?
2162 return nullptr;
2163 }
35e4f3b4
JP
2164 }
2165 }
2166 case RIGHT_PAREN:
2167 case RIGHT_SQUARE:
2168 case RIGHT_CURLY:
2169 // not allowed
2170 add_error (Error (
2171 t->get_locus (),
2172 "closing delimiters like %qs are not allowed at the start of a macro "
2173 "match",
2174 t->get_token_description ()));
2175
2176 // skip somewhere?
2177 return nullptr;
2178 default:
2179 // just the token
2180 lexer.skip_token ();
2181 return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
2182 }
2183}
2184
2185// Parses a fragment macro match.
2186template <typename ManagedTokenSource>
2187std::unique_ptr<AST::MacroMatchFragment>
2188Parser<ManagedTokenSource>::parse_macro_match_fragment ()
2189{
80c68893 2190 location_t fragment_locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
2191 skip_token (DOLLAR_SIGN);
2192
1c3a8fbb 2193 Identifier ident;
35e4f3b4 2194 auto identifier = lexer.peek_token ();
dfd2e26b 2195 if (identifier->get_id () == UNDERSCORE)
f1c7ce7e 2196 ident = {Values::Keywords::UNDERSCORE, identifier->get_locus ()};
35e4f3b4 2197 else
1c3a8fbb 2198 ident = {identifier};
35e4f3b4
JP
2199
2200 if (ident.empty ())
2201 {
2202 Error error (lexer.peek_token ()->get_locus (),
2203 "missing identifier in macro match fragment");
2204 add_error (std::move (error));
2205
2206 return nullptr;
2207 }
2208 skip_token (identifier->get_id ());
2209
2210 if (!skip_token (COLON))
2211 {
2212 // skip after somewhere?
2213 return nullptr;
2214 }
2215
2216 // get MacroFragSpec for macro
2217 const_TokenPtr t = expect_token (IDENTIFIER);
2218 if (t == nullptr)
2219 return nullptr;
2220
2221 AST::MacroFragSpec frag
2222 = AST::MacroFragSpec::get_frag_spec_from_str (t->get_str ());
2223 if (frag.is_error ())
2224 {
2225 Error error (t->get_locus (),
2226 "invalid fragment specifier %qs in fragment macro match",
2227 t->get_str ().c_str ());
2228 add_error (std::move (error));
2229
2230 return nullptr;
2231 }
2232
2233 return std::unique_ptr<AST::MacroMatchFragment> (
2234 new AST::MacroMatchFragment (std::move (ident), frag, fragment_locus));
2235}
2236
2237// Parses a repetition macro match.
2238template <typename ManagedTokenSource>
2239std::unique_ptr<AST::MacroMatchRepetition>
2240Parser<ManagedTokenSource>::parse_macro_match_repetition ()
2241{
2242 skip_token (DOLLAR_SIGN);
2243 skip_token (LEFT_PAREN);
2244
2245 std::vector<std::unique_ptr<AST::MacroMatch>> matches;
2246
2247 // parse required first macro match
2248 std::unique_ptr<AST::MacroMatch> initial_match = parse_macro_match ();
2249 if (initial_match == nullptr)
2250 {
2251 Error error (
2252 lexer.peek_token ()->get_locus (),
2253 "could not parse required first macro match in macro match repetition");
2254 add_error (std::move (error));
2255
2256 // skip after somewhere?
2257 return nullptr;
2258 }
2259 matches.push_back (std::move (initial_match));
2260
2261 // parse optional later macro matches
2262 const_TokenPtr t = lexer.peek_token ();
2263 while (t->get_id () != RIGHT_PAREN)
2264 {
2265 std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
2266
2267 if (match == nullptr)
2268 {
2269 Error error (lexer.peek_token ()->get_locus (),
2270 "failed to parse macro match in macro match repetition");
2271 add_error (std::move (error));
2272
2273 return nullptr;
2274 }
2275
2276 matches.push_back (std::move (match));
2277
2278 t = lexer.peek_token ();
2279 }
2280
2281 if (!skip_token (RIGHT_PAREN))
2282 {
2283 // skip after somewhere?
2284 return nullptr;
2285 }
2286
2287 t = lexer.peek_token ();
2288 // see if separator token exists
2289 std::unique_ptr<AST::Token> separator = nullptr;
2290 switch (t->get_id ())
2291 {
2292 // repetition operators
2293 case ASTERISK:
2294 case PLUS:
2295 case QUESTION_MARK:
2296 // delimiters
2297 case LEFT_PAREN:
2298 case LEFT_CURLY:
2299 case LEFT_SQUARE:
2300 case RIGHT_PAREN:
2301 case RIGHT_CURLY:
2302 case RIGHT_SQUARE:
2303 // separator does not exist, so still null and don't skip token
2304 break;
2305 default:
2306 // separator does exist
2307 separator = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
2308 lexer.skip_token ();
2309 break;
2310 }
2311
2312 // parse repetition operator
2313 t = lexer.peek_token ();
2314 AST::MacroMatchRepetition::MacroRepOp op = AST::MacroMatchRepetition::NONE;
2315 switch (t->get_id ())
2316 {
2317 case ASTERISK:
2318 op = AST::MacroMatchRepetition::ANY;
2319 lexer.skip_token ();
2320 break;
2321 case PLUS:
2322 op = AST::MacroMatchRepetition::ONE_OR_MORE;
2323 lexer.skip_token ();
2324 break;
2325 case QUESTION_MARK:
2326 op = AST::MacroMatchRepetition::ZERO_OR_ONE;
2327 lexer.skip_token ();
694063d8
SK
2328
2329 if (separator != nullptr)
2330 {
2331 add_error (
2332 Error (separator->get_locus (),
2333 "the %<?%> macro repetition operator does not take a "
2334 "separator"));
2335 separator = nullptr;
2336 }
2337
35e4f3b4
JP
2338 break;
2339 default:
2340 add_error (
2341 Error (t->get_locus (),
2342 "expected macro repetition operator (%<*%>, %<+%>, or %<?%>) in "
2343 "macro match - found %qs",
2344 t->get_token_description ()));
2345
2346 // skip after somewhere?
2347 return nullptr;
2348 }
2349
2350 return std::unique_ptr<AST::MacroMatchRepetition> (
2351 new AST::MacroMatchRepetition (std::move (matches), op,
2352 std::move (separator), t->get_locus ()));
2353}
2354
2355/* Parses a visibility syntactical production (i.e. creating a non-default
2356 * visibility) */
2357template <typename ManagedTokenSource>
2358AST::Visibility
2359Parser<ManagedTokenSource>::parse_visibility ()
2360{
2361 // check for no visibility
2362 if (lexer.peek_token ()->get_id () != PUB)
2363 {
2364 return AST::Visibility::create_private ();
2365 }
2366
78c70a50 2367 auto vis_loc = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
2368 lexer.skip_token ();
2369
f209a018
PEP
2370 // create simple pub visibility if
2371 // - found no parentheses
2372 // - found unit type `()`
2373 if (lexer.peek_token ()->get_id () != LEFT_PAREN
2374 || lexer.peek_token (1)->get_id () == RIGHT_PAREN)
35e4f3b4 2375 {
78c70a50 2376 return AST::Visibility::create_public (vis_loc);
35e4f3b4
JP
2377 // or whatever
2378 }
2379
2380 lexer.skip_token ();
2381
2382 const_TokenPtr t = lexer.peek_token ();
2383 auto path_loc = t->get_locus ();
2384
2385 switch (t->get_id ())
2386 {
2387 case CRATE:
2388 lexer.skip_token ();
2389
2390 skip_token (RIGHT_PAREN);
2391
78c70a50 2392 return AST::Visibility::create_crate (path_loc, vis_loc);
35e4f3b4
JP
2393 case SELF:
2394 lexer.skip_token ();
2395
2396 skip_token (RIGHT_PAREN);
2397
78c70a50 2398 return AST::Visibility::create_self (path_loc, vis_loc);
35e4f3b4
JP
2399 case SUPER:
2400 lexer.skip_token ();
2401
2402 skip_token (RIGHT_PAREN);
2403
78c70a50 2404 return AST::Visibility::create_super (path_loc, vis_loc);
35e4f3b4
JP
2405 case IN: {
2406 lexer.skip_token ();
2407
2408 // parse the "in" path as well
2409 AST::SimplePath path = parse_simple_path ();
2410 if (path.is_empty ())
2411 {
2412 Error error (lexer.peek_token ()->get_locus (),
2413 "missing path in pub(in path) visibility");
2414 add_error (std::move (error));
2415
2416 // skip after somewhere?
2417 return AST::Visibility::create_error ();
2418 }
2419
2420 skip_token (RIGHT_PAREN);
2421
78c70a50 2422 return AST::Visibility::create_in_path (std::move (path), vis_loc);
35e4f3b4
JP
2423 }
2424 default:
2425 add_error (Error (t->get_locus (), "unexpected token %qs in visibility",
2426 t->get_token_description ()));
2427
2428 lexer.skip_token ();
2429 return AST::Visibility::create_error ();
2430 }
2431}
2432
2433// Parses a module - either a bodied module or a module defined in another file.
2434template <typename ManagedTokenSource>
2435std::unique_ptr<AST::Module>
2436Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
2437 AST::AttrVec outer_attrs)
2438{
5959f32d
PEP
2439 location_t locus = lexer.peek_token ()->get_locus ();
2440
d6a0d965
PEP
2441 Unsafety safety = Unsafety::Normal;
2442 if (lexer.peek_token ()->get_id () == UNSAFE)
2443 {
2444 safety = Unsafety::Unsafe;
2445 skip_token (UNSAFE);
2446 }
2447
35e4f3b4
JP
2448 skip_token (MOD);
2449
2450 const_TokenPtr module_name = expect_token (IDENTIFIER);
2451 if (module_name == nullptr)
2452 {
2453 return nullptr;
2454 }
1c3a8fbb 2455 Identifier name{module_name};
35e4f3b4
JP
2456
2457 const_TokenPtr t = lexer.peek_token ();
2458
2459 switch (t->get_id ())
2460 {
2461 case SEMICOLON:
2462 lexer.skip_token ();
2463
2464 // Construct an external module
2465 return std::unique_ptr<AST::Module> (
2466 new AST::Module (std::move (name), std::move (vis),
d6a0d965 2467 std::move (outer_attrs), locus, safety,
7a4c2f8e 2468 lexer.get_filename (), inline_module_stack));
35e4f3b4
JP
2469 case LEFT_CURLY: {
2470 lexer.skip_token ();
2471
2472 // parse inner attributes
2473 AST::AttrVec inner_attrs = parse_inner_attributes ();
2474
fcb228d1 2475 std::string default_path = name.as_string ();
e6d40678
OA
2476
2477 if (inline_module_stack.empty ())
2478 {
2479 std::string filename = lexer.get_filename ();
2480 auto slash_idx = filename.rfind (file_separator);
2481 if (slash_idx == std::string::npos)
2482 slash_idx = 0;
2483 else
2484 slash_idx++;
2485 filename = filename.substr (slash_idx);
2486
2487 std::string subdir;
2488 if (get_file_subdir (filename, subdir))
fcb228d1 2489 default_path = subdir + file_separator + name.as_string ();
e6d40678
OA
2490 }
2491
35e4f3b4 2492 std::string module_path_name
e6d40678 2493 = extract_module_path (inner_attrs, outer_attrs, default_path);
35e4f3b4
JP
2494 InlineModuleStackScope scope (*this, std::move (module_path_name));
2495
2496 // parse items
2497 std::vector<std::unique_ptr<AST::Item>> items;
2498 const_TokenPtr tok = lexer.peek_token ();
2499 while (tok->get_id () != RIGHT_CURLY)
2500 {
2501 std::unique_ptr<AST::Item> item = parse_item (false);
2502 if (item == nullptr)
2503 {
2504 Error error (tok->get_locus (),
2505 "failed to parse item in module");
2506 add_error (std::move (error));
2507
2508 return nullptr;
2509 }
2510
2511 items.push_back (std::move (item));
2512
2513 tok = lexer.peek_token ();
2514 }
2515
2516 if (!skip_token (RIGHT_CURLY))
2517 {
2518 // skip somewhere?
2519 return nullptr;
2520 }
2521
2522 return std::unique_ptr<AST::Module> (
2523 new AST::Module (std::move (name), locus, std::move (items),
d6a0d965 2524 std::move (vis), safety, std::move (inner_attrs),
35e4f3b4
JP
2525 std::move (outer_attrs))); // module name?
2526 }
2527 default:
2528 add_error (
2529 Error (t->get_locus (),
2530 "unexpected token %qs in module declaration/definition item",
2531 t->get_token_description ()));
2532
2533 lexer.skip_token ();
2534 return nullptr;
2535 }
2536}
2537
2538// Parses an extern crate declaration (dependency on external crate)
2539template <typename ManagedTokenSource>
2540std::unique_ptr<AST::ExternCrate>
2541Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis,
2542 AST::AttrVec outer_attrs)
2543{
d991a3f1 2544 location_t locus = lexer.peek_token ()->get_locus ();
7f631967 2545 if (!skip_token (EXTERN_KW))
35e4f3b4
JP
2546 {
2547 skip_after_semicolon ();
2548 return nullptr;
2549 }
2550
2551 if (!skip_token (CRATE))
2552 {
2553 skip_after_semicolon ();
2554 return nullptr;
2555 }
2556
2557 /* parse crate reference name - this has its own syntactical rule in reference
2558 * but seems to not be used elsewhere, so i'm putting it here */
2559 const_TokenPtr crate_name_tok = lexer.peek_token ();
2560 std::string crate_name;
2561
2562 switch (crate_name_tok->get_id ())
2563 {
2564 case IDENTIFIER:
2565 crate_name = crate_name_tok->get_str ();
2566 lexer.skip_token ();
2567 break;
2568 case SELF:
f1c7ce7e 2569 crate_name = Values::Keywords::SELF;
35e4f3b4
JP
2570 lexer.skip_token ();
2571 break;
2572 default:
2573 add_error (
2574 Error (crate_name_tok->get_locus (),
2575 "expecting crate name (identifier or %<self%>), found %qs",
2576 crate_name_tok->get_token_description ()));
2577
2578 skip_after_semicolon ();
2579 return nullptr;
2580 }
2581
2582 // don't parse as clause if it doesn't exist
2583 if (lexer.peek_token ()->get_id () == SEMICOLON)
2584 {
2585 lexer.skip_token ();
2586
2587 return std::unique_ptr<AST::ExternCrate> (
2588 new AST::ExternCrate (std::move (crate_name), std::move (vis),
2589 std::move (outer_attrs), locus));
2590 }
2591
2592 /* parse as clause - this also has its own syntactical rule in reference and
2593 * also seems to not be used elsewhere, so including here again. */
2594 if (!skip_token (AS))
2595 {
2596 skip_after_semicolon ();
2597 return nullptr;
2598 }
2599
2600 const_TokenPtr as_name_tok = lexer.peek_token ();
2601 std::string as_name;
2602
2603 switch (as_name_tok->get_id ())
2604 {
2605 case IDENTIFIER:
2606 as_name = as_name_tok->get_str ();
2607 lexer.skip_token ();
2608 break;
2609 case UNDERSCORE:
f1c7ce7e 2610 as_name = Values::Keywords::UNDERSCORE;
35e4f3b4
JP
2611 lexer.skip_token ();
2612 break;
2613 default:
2614 add_error (
2615 Error (as_name_tok->get_locus (),
2616 "expecting as clause name (identifier or %<_%>), found %qs",
2617 as_name_tok->get_token_description ()));
2618
2619 skip_after_semicolon ();
2620 return nullptr;
2621 }
2622
2623 if (!skip_token (SEMICOLON))
2624 {
2625 skip_after_semicolon ();
2626 return nullptr;
2627 }
2628
2629 return std::unique_ptr<AST::ExternCrate> (
2630 new AST::ExternCrate (std::move (crate_name), std::move (vis),
2631 std::move (outer_attrs), locus, std::move (as_name)));
2632}
2633
2634// Parses a use declaration.
2635template <typename ManagedTokenSource>
2636std::unique_ptr<AST::UseDeclaration>
2637Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
2638 AST::AttrVec outer_attrs)
2639{
d991a3f1 2640 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
2641 if (!skip_token (USE))
2642 {
2643 skip_after_semicolon ();
2644 return nullptr;
2645 }
2646
2647 // parse use tree, which is required
2648 std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
2649 if (use_tree == nullptr)
2650 {
2651 Error error (lexer.peek_token ()->get_locus (),
2652 "could not parse use tree in use declaration");
2653 add_error (std::move (error));
2654
2655 skip_after_semicolon ();
2656 return nullptr;
2657 }
2658
2659 if (!skip_token (SEMICOLON))
2660 {
2661 skip_after_semicolon ();
2662 return nullptr;
2663 }
2664
2665 return std::unique_ptr<AST::UseDeclaration> (
2666 new AST::UseDeclaration (std::move (use_tree), std::move (vis),
2667 std::move (outer_attrs), locus));
2668}
2669
2670// Parses a use tree (which can be recursive and is actually a base class).
2671template <typename ManagedTokenSource>
2672std::unique_ptr<AST::UseTree>
2673Parser<ManagedTokenSource>::parse_use_tree ()
2674{
2675 /* potential syntax definitions in attempt to get algorithm:
2676 * Glob:
2677 * <- SimplePath :: *
2678 * <- :: *
2679 * <- *
2680 * Nested tree thing:
2681 * <- SimplePath :: { COMPLICATED_INNER_TREE_THING }
2682 * <- :: COMPLICATED_INNER_TREE_THING }
2683 * <- { COMPLICATED_INNER_TREE_THING }
2684 * Rebind thing:
2685 * <- SimplePath as IDENTIFIER
2686 * <- SimplePath as _
2687 * <- SimplePath
2688 */
2689
2690 /* current plan of attack: try to parse SimplePath first - if fails, one of
2691 * top two then try parse :: - if fails, one of top two. Next is deciding
2692 * character for top two. */
2693
2694 /* Thus, parsing smaller parts of use tree may require feeding into function
2695 * via parameters (or could handle all in this single function because other
2696 * use tree types aren't recognised as separate in the spec) */
2697
2698 // TODO: I think this function is too complex, probably should split it
2699
d991a3f1 2700 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
2701
2702 // bool has_path = false;
2703 AST::SimplePath path = parse_simple_path ();
2704
2705 if (path.is_empty ())
2706 {
2707 // has no path, so must be glob or nested tree UseTree type
2708
2709 bool is_global = false;
2710
2711 // check for global scope resolution operator
2712 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
2713 {
2714 lexer.skip_token ();
2715 is_global = true;
2716 }
2717
2718 const_TokenPtr t = lexer.peek_token ();
2719 switch (t->get_id ())
2720 {
2721 case ASTERISK:
2722 // glob UseTree type
2723 lexer.skip_token ();
2724
2725 if (is_global)
2726 return std::unique_ptr<AST::UseTreeGlob> (
2727 new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL,
2728 AST::SimplePath::create_empty (), locus));
2729 else
2730 return std::unique_ptr<AST::UseTreeGlob> (
2731 new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH,
2732 AST::SimplePath::create_empty (), locus));
2733 case LEFT_CURLY: {
2734 // nested tree UseTree type
2735 lexer.skip_token ();
2736
2737 std::vector<std::unique_ptr<AST::UseTree>> use_trees;
2738
2739 const_TokenPtr t = lexer.peek_token ();
2740 while (t->get_id () != RIGHT_CURLY)
2741 {
2742 std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
2743 if (use_tree == nullptr)
2744 {
2745 break;
2746 }
2747
2748 use_trees.push_back (std::move (use_tree));
2749
2750 if (lexer.peek_token ()->get_id () != COMMA)
2751 break;
2752
2753 lexer.skip_token ();
2754 t = lexer.peek_token ();
2755 }
2756
2757 // skip end curly delimiter
2758 if (!skip_token (RIGHT_CURLY))
2759 {
2760 // skip after somewhere?
2761 return nullptr;
2762 }
2763
2764 if (is_global)
2765 return std::unique_ptr<AST::UseTreeList> (
2766 new AST::UseTreeList (AST::UseTreeList::GLOBAL,
2767 AST::SimplePath::create_empty (),
2768 std::move (use_trees), locus));
2769 else
2770 return std::unique_ptr<AST::UseTreeList> (
2771 new AST::UseTreeList (AST::UseTreeList::NO_PATH,
2772 AST::SimplePath::create_empty (),
2773 std::move (use_trees), locus));
2774 }
2775 case AS:
2776 // this is not allowed
2777 add_error (Error (
2778 t->get_locus (),
2779 "use declaration with rebind %<as%> requires a valid simple path - "
2780 "none found"));
2781
2782 skip_after_semicolon ();
2783 return nullptr;
2784 default:
2785 add_error (Error (t->get_locus (),
2786 "unexpected token %qs in use tree with "
2787 "no valid simple path (i.e. list"
2788 " or glob use tree)",
2789 t->get_token_description ()));
2790
2791 skip_after_semicolon ();
2792 return nullptr;
2793 }
2794 }
2795 else
2796 {
2797 /* Due to aforementioned implementation issues, the trailing :: token is
2798 * consumed by the path, so it can not be used as a disambiguator.
2799 * NOPE, not true anymore - TODO what are the consequences of this? */
2800
2801 const_TokenPtr t = lexer.peek_token ();
2802 switch (t->get_id ())
2803 {
2804 case ASTERISK:
2805 // glob UseTree type
2806 lexer.skip_token ();
2807
2808 return std::unique_ptr<AST::UseTreeGlob> (
2809 new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
2810 std::move (path), locus));
2811 case LEFT_CURLY: {
2812 // nested tree UseTree type
2813 lexer.skip_token ();
2814
2815 std::vector<std::unique_ptr<AST::UseTree>> use_trees;
2816
2817 // TODO: think of better control structure
2818 const_TokenPtr t = lexer.peek_token ();
2819 while (t->get_id () != RIGHT_CURLY)
2820 {
2821 std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
2822 if (use_tree == nullptr)
2823 {
2824 break;
2825 }
2826
2827 use_trees.push_back (std::move (use_tree));
2828
2829 if (lexer.peek_token ()->get_id () != COMMA)
2830 break;
2831
2832 lexer.skip_token ();
2833 t = lexer.peek_token ();
2834 }
2835
2836 // skip end curly delimiter
2837 if (!skip_token (RIGHT_CURLY))
2838 {
2839 // skip after somewhere?
2840 return nullptr;
2841 }
2842
2843 return std::unique_ptr<AST::UseTreeList> (
2844 new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED,
2845 std::move (path), std::move (use_trees),
2846 locus));
2847 }
2848 case AS: {
2849 // rebind UseTree type
2850 lexer.skip_token ();
2851
2852 const_TokenPtr t = lexer.peek_token ();
2853 switch (t->get_id ())
2854 {
2855 case IDENTIFIER:
2856 // skip lexer token
2857 lexer.skip_token ();
2858
2859 return std::unique_ptr<AST::UseTreeRebind> (
2860 new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER,
1c3a8fbb 2861 std::move (path), locus, t));
35e4f3b4
JP
2862 case UNDERSCORE:
2863 // skip lexer token
2864 lexer.skip_token ();
2865
2866 return std::unique_ptr<AST::UseTreeRebind> (
2867 new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD,
1c3a8fbb 2868 std::move (path), locus,
f1c7ce7e
PEP
2869 {Values::Keywords::UNDERSCORE,
2870 t->get_locus ()}));
35e4f3b4
JP
2871 default:
2872 add_error (Error (
2873 t->get_locus (),
2874 "unexpected token %qs in use tree with as clause - expected "
2875 "identifier or %<_%>",
2876 t->get_token_description ()));
2877
2878 skip_after_semicolon ();
2879 return nullptr;
2880 }
2881 }
2882 case SEMICOLON:
2883 // rebind UseTree type without rebinding - path only
2884
2885 // don't skip semicolon - handled in parse_use_tree
2886 // lexer.skip_token();
2887
2888 return std::unique_ptr<AST::UseTreeRebind> (
2889 new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path),
2890 locus));
2891 case COMMA:
2892 case RIGHT_CURLY:
2893 // this may occur in recursive calls - assume it is ok and ignore it
2894 return std::unique_ptr<AST::UseTreeRebind> (
2895 new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path),
2896 locus));
2897 default:
2898 add_error (Error (t->get_locus (),
2899 "unexpected token %qs in use tree with valid path",
2900 t->get_token_description ()));
2901
2902 // skip_after_semicolon();
2903 return nullptr;
2904 }
2905 }
2906}
2907
2908// Parses a function (not a method).
2909template <typename ManagedTokenSource>
2910std::unique_ptr<AST::Function>
2911Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
bbc1dfcc 2912 AST::AttrVec outer_attrs,
2913 bool is_external)
35e4f3b4 2914{
d991a3f1 2915 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
2916 // Get qualifiers for function if they exist
2917 AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
2918
7f631967 2919 skip_token (FN_KW);
35e4f3b4
JP
2920
2921 // Save function name token
2922 const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
2923 if (function_name_tok == nullptr)
2924 {
2925 skip_after_next_block ();
2926 return nullptr;
2927 }
1c3a8fbb 2928 Identifier function_name{function_name_tok};
35e4f3b4
JP
2929
2930 // parse generic params - if exist
2931 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
2932 = parse_generic_params_in_angles ();
2933
2934 if (!skip_token (LEFT_PAREN))
2935 {
2936 Error error (lexer.peek_token ()->get_locus (),
2937 "function declaration missing opening parentheses before "
2938 "parameter list");
2939 add_error (std::move (error));
2940
2941 skip_after_next_block ();
2942 return nullptr;
2943 }
2944
3e450ae1
PEP
2945 auto initial_param = parse_self_param ();
2946
2947 if (!initial_param.has_value ()
2948 && initial_param.error () != ParseSelfError::NOT_SELF)
2949 return nullptr;
2950
f89186f9
KP
2951 if (initial_param.has_value () && lexer.peek_token ()->get_id () == COMMA)
2952 skip_token ();
513b0154 2953
35e4f3b4 2954 // parse function parameters (only if next token isn't right paren)
513b0154
PEP
2955 std::vector<std::unique_ptr<AST::Param>> function_params;
2956
35e4f3b4
JP
2957 if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
2958 function_params
2959 = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
2960
3e450ae1 2961 if (initial_param.has_value ())
513b0154 2962 function_params.insert (function_params.begin (),
3e450ae1 2963 std::move (*initial_param));
513b0154 2964
35e4f3b4
JP
2965 if (!skip_token (RIGHT_PAREN))
2966 {
2967 Error error (lexer.peek_token ()->get_locus (),
2968 "function declaration missing closing parentheses after "
2969 "parameter list");
2970 add_error (std::move (error));
2971
2972 skip_after_next_block ();
2973 return nullptr;
2974 }
2975
2976 // parse function return type - if exists
2977 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
2978
2979 // parse where clause - if exists
2980 AST::WhereClause where_clause = parse_where_clause ();
2981
7a989394
PEP
2982 tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
2983 if (lexer.peek_token ()->get_id () == SEMICOLON)
2984 lexer.skip_token ();
2985 else
2986 {
2987 std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
2988 if (block_expr != nullptr)
2989 body = std::move (block_expr);
2990 }
35e4f3b4
JP
2991
2992 return std::unique_ptr<AST::Function> (
2993 new AST::Function (std::move (function_name), std::move (qualifiers),
513b0154
PEP
2994 std::move (generic_params), std::move (function_params),
2995 std::move (return_type), std::move (where_clause),
7a989394 2996 std::move (body), std::move (vis),
bbc1dfcc 2997 std::move (outer_attrs), locus, false, is_external));
35e4f3b4
JP
2998}
2999
3000// Parses function or method qualifiers (i.e. const, unsafe, and extern).
3001template <typename ManagedTokenSource>
3002AST::FunctionQualifiers
3003Parser<ManagedTokenSource>::parse_function_qualifiers ()
3004{
12844c82
PEP
3005 Async async_status = Async::No;
3006 Const const_status = Const::No;
3007 Unsafety unsafe_status = Unsafety::Normal;
35e4f3b4
JP
3008 bool has_extern = false;
3009 std::string abi;
3010
12844c82
PEP
3011 const_TokenPtr t;
3012 location_t locus;
35e4f3b4 3013 // Check in order of const, unsafe, then extern
12844c82 3014 for (int i = 0; i < 2; i++)
35e4f3b4 3015 {
12844c82
PEP
3016 t = lexer.peek_token ();
3017 locus = t->get_locus ();
3018
3019 switch (t->get_id ())
3020 {
3021 case CONST:
3022 lexer.skip_token ();
3023 const_status = Const::Yes;
3024 break;
3025 case ASYNC:
3026 lexer.skip_token ();
3027 async_status = Async::Yes;
3028 break;
3029 default:
3030 // const status is still none
3031 break;
3032 }
35e4f3b4
JP
3033 }
3034
3035 if (lexer.peek_token ()->get_id () == UNSAFE)
3036 {
3037 lexer.skip_token ();
12844c82 3038 unsafe_status = Unsafety::Unsafe;
35e4f3b4
JP
3039 }
3040
7f631967 3041 if (lexer.peek_token ()->get_id () == EXTERN_KW)
35e4f3b4
JP
3042 {
3043 lexer.skip_token ();
3044 has_extern = true;
3045
3046 // detect optional abi name
3047 const_TokenPtr next_tok = lexer.peek_token ();
3048 if (next_tok->get_id () == STRING_LITERAL)
3049 {
3050 lexer.skip_token ();
3051 abi = next_tok->get_str ();
3052 }
3053 }
3054
12844c82
PEP
3055 return AST::FunctionQualifiers (locus, async_status, const_status,
3056 unsafe_status, has_extern, std::move (abi));
35e4f3b4
JP
3057}
3058
3059// Parses generic (lifetime or type) params inside angle brackets (optional).
3060template <typename ManagedTokenSource>
3061std::vector<std::unique_ptr<AST::GenericParam>>
3062Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
3063{
3064 if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
3065 {
3066 // seems to be no generic params, so exit with empty vector
3067 return std::vector<std::unique_ptr<AST::GenericParam>> ();
3068 }
3069 lexer.skip_token ();
3070
3071 // DEBUG:
3072 rust_debug ("skipped left angle in generic param");
3073
3074 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3075 = parse_generic_params (is_right_angle_tok);
3076
3077 // DEBUG:
3078 rust_debug ("finished parsing actual generic params (i.e. inside angles)");
3079
3080 if (!skip_generics_right_angle ())
3081 {
3082 // DEBUG
3083 rust_debug ("failed to skip generics right angle - returning empty "
3084 "generic params");
3085
3086 return std::vector<std::unique_ptr<AST::GenericParam>> ();
3087 }
3088
3089 return generic_params;
3090}
3091
3092template <typename ManagedTokenSource>
3093template <typename EndTokenPred>
3094std::unique_ptr<AST::GenericParam>
3095Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
3096{
6fef5bc4 3097 auto outer_attrs = parse_outer_attributes ();
35e4f3b4 3098 std::unique_ptr<AST::GenericParam> param;
f092edae 3099 auto token = lexer.peek_token ();
35e4f3b4
JP
3100
3101 switch (token->get_id ())
3102 {
3103 case LIFETIME: {
6def638e 3104 auto lifetime = parse_lifetime (false);
827ceac9 3105 if (!lifetime)
35e4f3b4
JP
3106 {
3107 rust_error_at (
3108 token->get_locus (),
3109 "failed to parse lifetime in generic parameter list");
3110 return nullptr;
3111 }
3112
3113 std::vector<AST::Lifetime> lifetime_bounds;
3114 if (lexer.peek_token ()->get_id () == COLON)
3115 {
3116 lexer.skip_token ();
3117 // parse required bounds
3118 lifetime_bounds
3119 = parse_lifetime_bounds ([is_end_token] (TokenId id) {
3120 return is_end_token (id) || id == COMMA;
3121 });
3122 }
3123
3124 param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam (
827ceac9 3125 std::move (lifetime.value ()), std::move (lifetime_bounds),
35e4f3b4
JP
3126 std::move (outer_attrs), token->get_locus ()));
3127 break;
3128 }
3129 case IDENTIFIER: {
3130 auto type_ident = token->get_str ();
3131 lexer.skip_token ();
3132
3133 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3134 if (lexer.peek_token ()->get_id () == COLON)
3135 {
3136 lexer.skip_token ();
3137
3138 // parse optional type param bounds
3139 type_param_bounds = parse_type_param_bounds ();
3140 }
3141
3142 std::unique_ptr<AST::Type> type = nullptr;
3143 if (lexer.peek_token ()->get_id () == EQUAL)
3144 {
3145 lexer.skip_token ();
3146
3147 // parse required type
3148 type = parse_type ();
3149 if (!type)
3150 {
3151 rust_error_at (
3152 lexer.peek_token ()->get_locus (),
3153 "failed to parse type in type param in generic params");
3154 return nullptr;
3155 }
3156 }
3157
3158 param = std::unique_ptr<AST::TypeParam> (
3159 new AST::TypeParam (std::move (type_ident), token->get_locus (),
3160 std::move (type_param_bounds), std::move (type),
3161 std::move (outer_attrs)));
3162 break;
3163 }
3164 case CONST: {
3165 lexer.skip_token ();
3166
3167 auto name_token = expect_token (IDENTIFIER);
3168
3169 if (!name_token || !expect_token (COLON))
3170 return nullptr;
3171
3172 auto type = parse_type ();
3173 if (!type)
3174 return nullptr;
3175
3176 // optional default value
e905c04b 3177 tl::optional<AST::GenericArg> default_expr = tl::nullopt;
35e4f3b4
JP
3178 if (lexer.peek_token ()->get_id () == EQUAL)
3179 {
3180 lexer.skip_token ();
3181 auto tok = lexer.peek_token ();
3182 default_expr = parse_generic_arg ();
3183
e905c04b
PEP
3184 if (!default_expr)
3185 {
3186 rust_error_at (tok->get_locus (),
3187 "invalid token for start of default value for "
3188 "const generic parameter: expected %<block%>, "
3189 "%<identifier%> or %<literal%>, got %qs",
3190 token_id_to_str (tok->get_id ()));
3191 return nullptr;
3192 }
35e4f3b4
JP
3193
3194 // At this point, we *know* that we are parsing a const
3195 // expression
e905c04b
PEP
3196 if (default_expr.value ().get_kind ()
3197 == AST::GenericArg::Kind::Either)
3198 default_expr = default_expr.value ().disambiguate_to_const ();
35e4f3b4
JP
3199 }
3200
3201 param = std::unique_ptr<AST::ConstGenericParam> (
3202 new AST::ConstGenericParam (name_token->get_str (), std::move (type),
3203 default_expr, std::move (outer_attrs),
3204 token->get_locus ()));
3205
3206 break;
3207 }
3208 default:
3209 // FIXME: Can we clean this last call with a method call?
3210 rust_error_at (token->get_locus (),
3211 "unexpected token when parsing generic parameters: %qs",
80199b32 3212 token->as_string ().c_str ());
35e4f3b4
JP
3213 return nullptr;
3214 }
3215
3216 return param;
3217}
3218
3219/* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost
3220 * always parse_generic_params_in_angles is what is wanted. */
3221template <typename ManagedTokenSource>
3222template <typename EndTokenPred>
3223std::vector<std::unique_ptr<AST::GenericParam>>
3224Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
3225{
3226 std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
3227
3228 /* can't parse lifetime and type params separately due to lookahead issues
3229 * thus, parse them all here */
3230
3231 /* HACK: used to retain attribute data if a lifetime param is tentatively
3232 * parsed but it turns out to be type param */
3233 AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
3234
3235 // Did we parse a generic type param yet
3236 auto type_seen = false;
3237 // Did the user write a lifetime parameter after a type one
3238 auto order_error = false;
3239
3240 // parse lifetime params
3241 while (!is_end_token (lexer.peek_token ()->get_id ()))
3242 {
3243 auto param = parse_generic_param (is_end_token);
3244 if (param)
3245 {
3246 // TODO: Handle `Const` here as well if necessary
3247 if (param->get_kind () == AST::GenericParam::Kind::Type)
3248 type_seen = true;
3249 else if (param->get_kind () == AST::GenericParam::Kind::Lifetime
3250 && type_seen)
3251 order_error = true;
3252
3253 generic_params.emplace_back (std::move (param));
3254 maybe_skip_token (COMMA);
3255 }
582acced
OA
3256 else
3257 break;
35e4f3b4
JP
3258 }
3259
3260 // FIXME: Add reordering hint
3261 if (order_error)
c7c9bbaa
MM
3262 {
3263 Error error (generic_params.front ()->get_locus (),
3264 "invalid order for generic parameters: lifetime parameters "
3265 "must be declared prior to type and const parameters");
3266 add_error (std::move (error));
3267 }
35e4f3b4
JP
3268
3269 generic_params.shrink_to_fit ();
3270 return generic_params;
3271}
3272
3273/* Parses lifetime generic parameters (pointers). Will also consume any
3274 * trailing comma. No extra checks for end token. */
3275template <typename ManagedTokenSource>
3276std::vector<std::unique_ptr<AST::LifetimeParam>>
3277Parser<ManagedTokenSource>::parse_lifetime_params ()
3278{
3279 std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
3280
3281 while (lexer.peek_token ()->get_id () != END_OF_FILE)
3282 {
827ceac9 3283 auto lifetime_param = parse_lifetime_param ();
35e4f3b4 3284
827ceac9 3285 if (!lifetime_param)
35e4f3b4
JP
3286 {
3287 // can't treat as error as only way to get out with trailing comma
3288 break;
3289 }
3290
3291 lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> (
827ceac9 3292 new AST::LifetimeParam (std::move (lifetime_param.value ()))));
35e4f3b4
JP
3293
3294 if (lexer.peek_token ()->get_id () != COMMA)
3295 break;
3296
3297 // skip commas, including trailing commas
3298 lexer.skip_token ();
3299 }
3300
3301 lifetime_params.shrink_to_fit ();
3302
3303 return lifetime_params;
3304}
3305
3306/* Parses lifetime generic parameters (pointers). Will also consume any
3307 * trailing comma. Has extra is_end_token predicate checking. */
3308template <typename ManagedTokenSource>
3309template <typename EndTokenPred>
3310std::vector<std::unique_ptr<AST::LifetimeParam>>
3311Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token)
3312{
3313 std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
3314
3315 // if end_token is not specified, it defaults to EOF, so should work fine
3316 while (!is_end_token (lexer.peek_token ()->get_id ()))
3317 {
827ceac9 3318 auto lifetime_param = parse_lifetime_param ();
35e4f3b4 3319
827ceac9 3320 if (!lifetime_param)
35e4f3b4
JP
3321 {
3322 /* TODO: is it worth throwing away all lifetime params just because
3323 * one failed? */
3324 Error error (lexer.peek_token ()->get_locus (),
3325 "failed to parse lifetime param in lifetime params");
3326 add_error (std::move (error));
3327
3328 return {};
3329 }
3330
3331 lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> (
3332 new AST::LifetimeParam (std::move (lifetime_param))));
3333
3334 if (lexer.peek_token ()->get_id () != COMMA)
3335 break;
3336
3337 // skip commas, including trailing commas
3338 lexer.skip_token ();
3339 }
3340
3341 lifetime_params.shrink_to_fit ();
3342
3343 return lifetime_params;
3344}
3345
3346/* Parses lifetime generic parameters (objects). Will also consume any
3347 * trailing comma. No extra checks for end token.
3348 * TODO: is this best solution? implements most of the same algorithm. */
3349template <typename ManagedTokenSource>
3350std::vector<AST::LifetimeParam>
3351Parser<ManagedTokenSource>::parse_lifetime_params_objs ()
3352{
3353 std::vector<AST::LifetimeParam> lifetime_params;
3354
3355 // bad control structure as end token cannot be guaranteed
3356 while (true)
3357 {
827ceac9 3358 auto lifetime_param = parse_lifetime_param ();
35e4f3b4 3359
827ceac9 3360 if (!lifetime_param)
35e4f3b4
JP
3361 {
3362 // not an error as only way to exit if trailing comma
3363 break;
3364 }
3365
3366 lifetime_params.push_back (std::move (lifetime_param));
3367
3368 if (lexer.peek_token ()->get_id () != COMMA)
3369 break;
3370
3371 // skip commas, including trailing commas
3372 lexer.skip_token ();
3373 }
3374
3375 lifetime_params.shrink_to_fit ();
3376
3377 return lifetime_params;
3378}
3379
3380/* Parses lifetime generic parameters (objects). Will also consume any
3381 * trailing comma. Has extra is_end_token predicate checking.
3382 * TODO: is this best solution? implements most of the same algorithm. */
3383template <typename ManagedTokenSource>
3384template <typename EndTokenPred>
3385std::vector<AST::LifetimeParam>
3386Parser<ManagedTokenSource>::parse_lifetime_params_objs (
3387 EndTokenPred is_end_token)
3388{
3389 std::vector<AST::LifetimeParam> lifetime_params;
3390
3391 while (!is_end_token (lexer.peek_token ()->get_id ()))
3392 {
827ceac9 3393 auto lifetime_param = parse_lifetime_param ();
35e4f3b4 3394
827ceac9 3395 if (!lifetime_param)
35e4f3b4
JP
3396 {
3397 /* TODO: is it worth throwing away all lifetime params just because
3398 * one failed? */
3399 Error error (lexer.peek_token ()->get_locus (),
3400 "failed to parse lifetime param in lifetime params");
3401 add_error (std::move (error));
3402
3403 return {};
3404 }
3405
827ceac9 3406 lifetime_params.push_back (std::move (lifetime_param.value ()));
35e4f3b4
JP
3407
3408 if (lexer.peek_token ()->get_id () != COMMA)
3409 break;
3410
3411 // skip commas, including trailing commas
3412 lexer.skip_token ();
3413 }
3414
3415 lifetime_params.shrink_to_fit ();
3416
3417 return lifetime_params;
3418}
3419
3420/* Parses a sequence of a certain grammar rule in object form (not pointer or
3421 * smart pointer), delimited by commas and ending when 'is_end_token' is
3422 * satisfied (templated). Will also consume any trailing comma.
3423 * FIXME: this cannot be used due to member function pointer problems (i.e.
3424 * parsing_function cannot be specified properly) */
3425template <typename ManagedTokenSource>
3426template <typename ParseFunction, typename EndTokenPred>
3427auto
3428Parser<ManagedTokenSource>::parse_non_ptr_sequence (
3429 ParseFunction parsing_function, EndTokenPred is_end_token,
3430 std::string error_msg) -> std::vector<decltype (parsing_function ())>
3431{
3432 std::vector<decltype (parsing_function ())> params;
3433
3434 while (!is_end_token (lexer.peek_token ()->get_id ()))
3435 {
3436 auto param = parsing_function ();
3437
3438 if (param.is_error ())
3439 {
3440 // TODO: is it worth throwing away all params just because one
3441 // failed?
3442 Error error (lexer.peek_token ()->get_locus (),
3443 std::move (error_msg));
3444 add_error (std::move (error));
3445
3446 return {};
3447 }
3448
3449 params.push_back (std::move (param));
3450
3451 if (lexer.peek_token ()->get_id () != COMMA)
3452 break;
3453
3454 // skip commas, including trailing commas
3455 lexer.skip_token ();
3456 }
3457
3458 params.shrink_to_fit ();
3459
3460 return params;
3461}
3462
3463/* Parses a single lifetime generic parameter (not including comma). */
3464template <typename ManagedTokenSource>
827ceac9 3465tl::expected<AST::LifetimeParam, ParseLifetimeParamError>
35e4f3b4
JP
3466Parser<ManagedTokenSource>::parse_lifetime_param ()
3467{
6fef5bc4
PEP
3468 // parse outer attributes, which are optional and may not exist
3469 auto outer_attrs = parse_outer_attributes ();
35e4f3b4
JP
3470
3471 // save lifetime token - required
3472 const_TokenPtr lifetime_tok = lexer.peek_token ();
3473 if (lifetime_tok->get_id () != LIFETIME)
3474 {
827ceac9
PEP
3475 // if lifetime is missing, must not be a lifetime param, so return error
3476 return tl::make_unexpected<ParseLifetimeParamError> ({});
35e4f3b4
JP
3477 }
3478 lexer.skip_token ();
35e4f3b4
JP
3479 AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (),
3480 lifetime_tok->get_locus ());
3481
3482 // parse lifetime bounds, if it exists
3483 std::vector<AST::Lifetime> lifetime_bounds;
3484 if (lexer.peek_token ()->get_id () == COLON)
3485 {
3486 // parse lifetime bounds
3487 lifetime_bounds = parse_lifetime_bounds ();
3488 // TODO: have end token passed in?
3489 }
3490
3491 return AST::LifetimeParam (std::move (lifetime), std::move (lifetime_bounds),
6fef5bc4 3492 std::move (outer_attrs),
35e4f3b4
JP
3493 lifetime_tok->get_locus ());
3494}
3495
3496// Parses type generic parameters. Will also consume any trailing comma.
3497template <typename ManagedTokenSource>
3498std::vector<std::unique_ptr<AST::TypeParam>>
3499Parser<ManagedTokenSource>::parse_type_params ()
3500{
3501 std::vector<std::unique_ptr<AST::TypeParam>> type_params;
3502
3503 // infinite loop with break on failure as no info on ending token
3504 while (true)
3505 {
3506 std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
3507
3508 if (type_param == nullptr)
3509 {
3510 // break if fails to parse
3511 break;
3512 }
3513
3514 type_params.push_back (std::move (type_param));
3515
3516 if (lexer.peek_token ()->get_id () != COMMA)
3517 break;
3518
3519 // skip commas, including trailing commas
3520 lexer.skip_token ();
3521 }
3522
3523 type_params.shrink_to_fit ();
3524 return type_params;
3525}
3526
3527// Parses type generic parameters. Will also consume any trailing comma.
3528template <typename ManagedTokenSource>
3529template <typename EndTokenPred>
3530std::vector<std::unique_ptr<AST::TypeParam>>
3531Parser<ManagedTokenSource>::parse_type_params (EndTokenPred is_end_token)
3532{
3533 std::vector<std::unique_ptr<AST::TypeParam>> type_params;
3534
3535 while (!is_end_token (lexer.peek_token ()->get_id ()))
3536 {
3537 std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
3538
3539 if (type_param == nullptr)
3540 {
3541 Error error (lexer.peek_token ()->get_locus (),
3542 "failed to parse type param in type params");
3543 add_error (std::move (error));
3544
3545 return {};
3546 }
3547
3548 type_params.push_back (std::move (type_param));
3549
3550 if (lexer.peek_token ()->get_id () != COMMA)
3551 break;
3552
3553 // skip commas, including trailing commas
3554 lexer.skip_token ();
3555 }
3556
3557 type_params.shrink_to_fit ();
3558 return type_params;
3559 /* TODO: this shares most code with parse_lifetime_params - good place to
3560 * use template (i.e. parse_non_ptr_sequence if doable) */
3561}
3562
3563/* Parses a single type (generic) parameter, not including commas. May change
3564 * to return value. */
3565template <typename ManagedTokenSource>
3566std::unique_ptr<AST::TypeParam>
3567Parser<ManagedTokenSource>::parse_type_param ()
3568{
6fef5bc4
PEP
3569 // parse outer attributes, which are optional and may not exist
3570 auto outer_attrs = parse_outer_attributes ();
35e4f3b4
JP
3571
3572 const_TokenPtr identifier_tok = lexer.peek_token ();
3573 if (identifier_tok->get_id () != IDENTIFIER)
3574 {
3575 // return null as type param can't exist without this required
3576 // identifier
3577 return nullptr;
3578 }
1c3a8fbb 3579 Identifier ident{identifier_tok};
35e4f3b4
JP
3580 lexer.skip_token ();
3581
3582 // parse type param bounds (if they exist)
3583 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3584 if (lexer.peek_token ()->get_id () == COLON)
3585 {
3586 lexer.skip_token ();
3587
3588 // parse type param bounds, which may or may not exist
3589 type_param_bounds = parse_type_param_bounds ();
3590 }
3591
3592 // parse type (if it exists)
3593 std::unique_ptr<AST::Type> type = nullptr;
3594 if (lexer.peek_token ()->get_id () == EQUAL)
3595 {
3596 lexer.skip_token ();
3597
3598 // parse type (now required)
3599 type = parse_type ();
3600 if (type == nullptr)
3601 {
3602 Error error (lexer.peek_token ()->get_locus (),
3603 "failed to parse type in type param");
3604 add_error (std::move (error));
3605
3606 return nullptr;
3607 }
3608 }
3609
3610 return std::unique_ptr<AST::TypeParam> (
3611 new AST::TypeParam (std::move (ident), identifier_tok->get_locus (),
3612 std::move (type_param_bounds), std::move (type),
6fef5bc4 3613 std::move (outer_attrs)));
35e4f3b4
JP
3614}
3615
3616/* Parses regular (i.e. non-generic) parameters in functions or methods. Also
3617 * has end token handling. */
3618template <typename ManagedTokenSource>
3619template <typename EndTokenPred>
513b0154 3620std::vector<std::unique_ptr<AST::Param>>
35e4f3b4
JP
3621Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
3622{
513b0154 3623 std::vector<std::unique_ptr<AST::Param>> params;
35e4f3b4
JP
3624
3625 if (is_end_token (lexer.peek_token ()->get_id ()))
3626 return params;
3627
513b0154 3628 auto initial_param = parse_function_param ();
35e4f3b4
JP
3629
3630 // Return empty parameter list if no parameter there
513b0154 3631 if (initial_param == nullptr)
35e4f3b4
JP
3632 {
3633 // TODO: is this an error?
3634 return params;
3635 }
3636
3637 params.push_back (std::move (initial_param));
3638
3639 // maybe think of a better control structure here - do-while with an initial
3640 // error state? basically, loop through parameter list until can't find any
3641 // more params
3642 const_TokenPtr t = lexer.peek_token ();
3643 while (t->get_id () == COMMA)
3644 {
3645 // skip comma if applies
3646 lexer.skip_token ();
3647
3648 // TODO: strictly speaking, shouldn't there be no trailing comma?
3649 if (is_end_token (lexer.peek_token ()->get_id ()))
3650 break;
3651
3652 // now, as right paren would break, function param is required
513b0154
PEP
3653 auto param = parse_function_param ();
3654 if (param == nullptr)
35e4f3b4
JP
3655 {
3656 Error error (lexer.peek_token ()->get_locus (),
3657 "failed to parse function param (in function params)");
3658 add_error (std::move (error));
3659
3660 // skip somewhere?
513b0154 3661 return std::vector<std::unique_ptr<AST::Param>> ();
35e4f3b4
JP
3662 }
3663
3664 params.push_back (std::move (param));
3665
3666 t = lexer.peek_token ();
3667 }
3668
3669 params.shrink_to_fit ();
3670 return params;
3671}
3672
3673/* Parses a single regular (i.e. non-generic) parameter in a function or
3674 * method, i.e. the "name: type" bit. Also handles it not existing. */
3675template <typename ManagedTokenSource>
513b0154 3676std::unique_ptr<AST::Param>
35e4f3b4
JP
3677Parser<ManagedTokenSource>::parse_function_param ()
3678{
3679 // parse outer attributes if they exist
3680 AST::AttrVec outer_attrs = parse_outer_attributes ();
3681
3682 // TODO: should saved location be at start of outer attributes or pattern?
d991a3f1 3683 location_t locus = lexer.peek_token ()->get_locus ();
6ac7d473
PEP
3684
3685 if (lexer.peek_token ()->get_id () == ELLIPSIS) // Unnamed variadic
3686 {
3687 lexer.skip_token (); // Skip ellipsis
c8721ccd 3688 return std::make_unique<AST::VariadicParam> (
513b0154 3689 AST::VariadicParam (std::move (outer_attrs), locus));
6ac7d473
PEP
3690 }
3691
35e4f3b4
JP
3692 std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
3693
3694 // create error function param if it doesn't exist
3695 if (param_pattern == nullptr)
3696 {
3697 // skip after something
513b0154 3698 return nullptr;
35e4f3b4
JP
3699 }
3700
3701 if (!skip_token (COLON))
3702 {
3703 // skip after something
513b0154 3704 return nullptr;
35e4f3b4
JP
3705 }
3706
6ac7d473 3707 if (lexer.peek_token ()->get_id () == ELLIPSIS) // Named variadic
35e4f3b4 3708 {
6ac7d473 3709 lexer.skip_token (); // Skip ellipsis
c8721ccd 3710 return std::make_unique<AST::VariadicParam> (
513b0154
PEP
3711 AST::VariadicParam (std::move (param_pattern), std::move (outer_attrs),
3712 locus));
6ac7d473
PEP
3713 }
3714 else
3715 {
3716 std::unique_ptr<AST::Type> param_type = parse_type ();
3717 if (param_type == nullptr)
3718 {
513b0154 3719 return nullptr;
6ac7d473 3720 }
c8721ccd 3721 return std::make_unique<AST::FunctionParam> (
513b0154
PEP
3722 AST::FunctionParam (std::move (param_pattern), std::move (param_type),
3723 std::move (outer_attrs), locus));
35e4f3b4 3724 }
35e4f3b4
JP
3725}
3726
3727/* Parses a function or method return type syntactical construction. Also
3728 * handles a function return type not existing. */
3729template <typename ManagedTokenSource>
3730std::unique_ptr<AST::Type>
3731Parser<ManagedTokenSource>::parse_function_return_type ()
3732{
3733 if (lexer.peek_token ()->get_id () != RETURN_TYPE)
3734 return nullptr;
3735
3736 // skip return type, as it now obviously exists
3737 lexer.skip_token ();
3738
3739 std::unique_ptr<AST::Type> type = parse_type ();
3740
3741 return type;
3742}
3743
3744/* Parses a "where clause" (in a function, struct, method, etc.). Also handles
3745 * a where clause not existing, in which it will return
3746 * WhereClause::create_empty(), which can be checked via
3747 * WhereClause::is_empty(). */
3748template <typename ManagedTokenSource>
3749AST::WhereClause
3750Parser<ManagedTokenSource>::parse_where_clause ()
3751{
3752 const_TokenPtr where_tok = lexer.peek_token ();
3753 if (where_tok->get_id () != WHERE)
3754 {
3755 // where clause doesn't exist, so create empty one
3756 return AST::WhereClause::create_empty ();
3757 }
3758
3759 lexer.skip_token ();
3760
3761 /* parse where clause items - this is not a separate rule in the reference
3762 * so won't be here */
3763 std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items;
3764
37d4cf48
JD
3765 std::vector<AST::LifetimeParam> for_lifetimes;
3766 if (lexer.peek_token ()->get_id () == FOR)
3767 for_lifetimes = parse_for_lifetimes ();
3768
35e4f3b4
JP
3769 /* HACK: where clauses end with a right curly or semicolon or equals in all
3770 * uses currently */
3771 const_TokenPtr t = lexer.peek_token ();
3772 while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON
3773 && t->get_id () != EQUAL)
3774 {
3775 std::unique_ptr<AST::WhereClauseItem> where_clause_item
37d4cf48 3776 = parse_where_clause_item (for_lifetimes);
35e4f3b4
JP
3777
3778 if (where_clause_item == nullptr)
3779 {
3780 Error error (t->get_locus (), "failed to parse where clause item");
3781 add_error (std::move (error));
3782
3783 return AST::WhereClause::create_empty ();
3784 }
3785
3786 where_clause_items.push_back (std::move (where_clause_item));
3787
3788 // also skip comma if it exists
3789 if (lexer.peek_token ()->get_id () != COMMA)
3790 break;
3791
3792 lexer.skip_token ();
3793 t = lexer.peek_token ();
3794 }
3795
3796 where_clause_items.shrink_to_fit ();
3797 return AST::WhereClause (std::move (where_clause_items));
3798}
3799
3800/* Parses a where clause item (lifetime or type bound). Does not parse any
3801 * commas. */
3802template <typename ManagedTokenSource>
3803std::unique_ptr<AST::WhereClauseItem>
37d4cf48
JD
3804Parser<ManagedTokenSource>::parse_where_clause_item (
3805 const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
35e4f3b4
JP
3806{
3807 // shitty cheat way of determining lifetime or type bound - test for
3808 // lifetime
3809 const_TokenPtr t = lexer.peek_token ();
3810
3811 if (t->get_id () == LIFETIME)
3812 return parse_lifetime_where_clause_item ();
3813 else
37d4cf48 3814 return parse_type_bound_where_clause_item (outer_for_lifetimes);
35e4f3b4
JP
3815}
3816
3817// Parses a lifetime where clause item.
3818template <typename ManagedTokenSource>
3819std::unique_ptr<AST::LifetimeWhereClauseItem>
3820Parser<ManagedTokenSource>::parse_lifetime_where_clause_item ()
3821{
827ceac9
PEP
3822 auto parsed_lifetime = parse_lifetime (false);
3823 if (!parsed_lifetime)
35e4f3b4
JP
3824 {
3825 // TODO: error here?
3826 return nullptr;
3827 }
827ceac9 3828 auto lifetime = parsed_lifetime.value ();
35e4f3b4
JP
3829
3830 if (!skip_token (COLON))
3831 {
3832 // TODO: skip after somewhere
3833 return nullptr;
3834 }
3835
3836 std::vector<AST::Lifetime> lifetime_bounds = parse_lifetime_bounds ();
3837 // TODO: have end token passed in?
3838
d991a3f1 3839 location_t locus = lifetime.get_locus ();
35e4f3b4
JP
3840
3841 return std::unique_ptr<AST::LifetimeWhereClauseItem> (
3842 new AST::LifetimeWhereClauseItem (std::move (lifetime),
3843 std::move (lifetime_bounds), locus));
3844}
3845
3846// Parses a type bound where clause item.
3847template <typename ManagedTokenSource>
3848std::unique_ptr<AST::TypeBoundWhereClauseItem>
37d4cf48
JD
3849Parser<ManagedTokenSource>::parse_type_bound_where_clause_item (
3850 const std::vector<AST::LifetimeParam> &outer_for_lifetimes)
35e4f3b4 3851{
37d4cf48 3852 std::vector<AST::LifetimeParam> for_lifetimes = outer_for_lifetimes;
35e4f3b4
JP
3853
3854 std::unique_ptr<AST::Type> type = parse_type ();
3855 if (type == nullptr)
3856 {
3857 return nullptr;
3858 }
3859
3860 if (!skip_token (COLON))
3861 {
3862 // TODO: skip after somewhere
3863 return nullptr;
3864 }
3865
37d4cf48
JD
3866 if (lexer.peek_token ()->get_id () == FOR)
3867 {
3868 auto for_lifetimes_inner = parse_for_lifetimes ();
3869 for_lifetimes.insert (for_lifetimes.end (), for_lifetimes_inner.begin (),
3870 for_lifetimes_inner.end ());
3871 }
3872
35e4f3b4
JP
3873 // parse type param bounds if they exist
3874 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds
3875 = parse_type_param_bounds ();
3876
d991a3f1 3877 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
3878
3879 return std::unique_ptr<AST::TypeBoundWhereClauseItem> (
3880 new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes),
3881 std::move (type),
3882 std::move (type_param_bounds), locus));
3883}
3884
3885// Parses a for lifetimes clause, including the for keyword and angle
3886// brackets.
3887template <typename ManagedTokenSource>
3888std::vector<AST::LifetimeParam>
3889Parser<ManagedTokenSource>::parse_for_lifetimes ()
3890{
3891 std::vector<AST::LifetimeParam> params;
3892
3893 if (!skip_token (FOR))
3894 {
3895 // skip after somewhere?
3896 return params;
3897 }
3898
3899 if (!skip_token (LEFT_ANGLE))
3900 {
3901 // skip after somewhere?
3902 return params;
3903 }
3904
3905 /* cannot specify end token due to parsing problems with '>' tokens being
3906 * nested */
3907 params = parse_lifetime_params_objs (is_right_angle_tok);
3908
3909 if (!skip_generics_right_angle ())
3910 {
3911 // DEBUG
3912 rust_debug ("failed to skip generics right angle after (supposedly) "
3913 "finished parsing where clause items");
3914 // ok, well this gets called.
3915
3916 // skip after somewhere?
3917 return params;
3918 }
3919
3920 return params;
3921}
3922
3923// Parses type parameter bounds in where clause or generic arguments.
3924template <typename ManagedTokenSource>
3925std::vector<std::unique_ptr<AST::TypeParamBound>>
3926Parser<ManagedTokenSource>::parse_type_param_bounds ()
3927{
3928 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3929
3930 std::unique_ptr<AST::TypeParamBound> initial_bound
3931 = parse_type_param_bound ();
3932
3933 // quick exit if null
3934 if (initial_bound == nullptr)
3935 {
3936 /* error? type param bounds must have at least one term, but are bounds
3937 * optional? */
3938 return type_param_bounds;
3939 }
3940 type_param_bounds.push_back (std::move (initial_bound));
3941
3942 while (lexer.peek_token ()->get_id () == PLUS)
3943 {
3944 lexer.skip_token ();
3945
3946 std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
3947 if (bound == nullptr)
3948 {
3949 /* not an error: bound is allowed to be null as trailing plus is
3950 * allowed */
3951 return type_param_bounds;
3952 }
3953
3954 type_param_bounds.push_back (std::move (bound));
3955 }
3956
3957 type_param_bounds.shrink_to_fit ();
3958 return type_param_bounds;
3959}
3960
3961/* Parses type parameter bounds in where clause or generic arguments, with end
3962 * token handling. */
3963template <typename ManagedTokenSource>
3964template <typename EndTokenPred>
3965std::vector<std::unique_ptr<AST::TypeParamBound>>
3966Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token)
3967{
3968 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3969
3970 std::unique_ptr<AST::TypeParamBound> initial_bound
3971 = parse_type_param_bound ();
3972
3973 // quick exit if null
3974 if (initial_bound == nullptr)
3975 {
3976 /* error? type param bounds must have at least one term, but are bounds
3977 * optional? */
3978 return type_param_bounds;
3979 }
3980 type_param_bounds.push_back (std::move (initial_bound));
3981
3982 while (lexer.peek_token ()->get_id () == PLUS)
3983 {
3984 lexer.skip_token ();
3985
3986 // break if end token character
3987 if (is_end_token (lexer.peek_token ()->get_id ()))
3988 break;
3989
3990 std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
3991 if (bound == nullptr)
3992 {
3993 // TODO how wise is it to ditch all bounds if only one failed?
3994 Error error (lexer.peek_token ()->get_locus (),
3995 "failed to parse type param bound in type param bounds");
3996 add_error (std::move (error));
3997
3998 return {};
3999 }
4000
4001 type_param_bounds.push_back (std::move (bound));
4002 }
4003
4004 type_param_bounds.shrink_to_fit ();
4005 return type_param_bounds;
4006}
4007
4008/* Parses a single type parameter bound in a where clause or generic argument.
4009 * Does not parse the '+' between arguments. */
4010template <typename ManagedTokenSource>
4011std::unique_ptr<AST::TypeParamBound>
4012Parser<ManagedTokenSource>::parse_type_param_bound ()
4013{
4014 // shitty cheat way of determining lifetime or trait bound - test for
4015 // lifetime
4016 const_TokenPtr t = lexer.peek_token ();
4017 switch (t->get_id ())
4018 {
4019 case LIFETIME:
4020 return std::unique_ptr<AST::Lifetime> (
827ceac9 4021 new AST::Lifetime (parse_lifetime (false).value ()));
35e4f3b4
JP
4022 case LEFT_PAREN:
4023 case QUESTION_MARK:
4024 case FOR:
4025 case IDENTIFIER:
4026 case SUPER:
4027 case SELF:
4028 case SELF_ALIAS:
4029 case CRATE:
4030 case DOLLAR_SIGN:
12650695 4031 case SCOPE_RESOLUTION:
35e4f3b4
JP
4032 return parse_trait_bound ();
4033 default:
4034 // don't error - assume this is fine TODO
4035 return nullptr;
4036 }
4037}
4038
4039// Parses a trait bound type param bound.
4040template <typename ManagedTokenSource>
4041std::unique_ptr<AST::TraitBound>
4042Parser<ManagedTokenSource>::parse_trait_bound ()
4043{
4044 bool has_parens = false;
4045 bool has_question_mark = false;
4046
d991a3f1 4047 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4 4048
37d4cf48
JD
4049 /* parse optional `for lifetimes`. */
4050 std::vector<AST::LifetimeParam> for_lifetimes;
4051 if (lexer.peek_token ()->get_id () == FOR)
4052 for_lifetimes = parse_for_lifetimes ();
4053
35e4f3b4
JP
4054 // handle trait bound being in parentheses
4055 if (lexer.peek_token ()->get_id () == LEFT_PAREN)
4056 {
4057 has_parens = true;
4058 lexer.skip_token ();
4059 }
4060
4061 // handle having question mark (optional)
4062 if (lexer.peek_token ()->get_id () == QUESTION_MARK)
4063 {
4064 has_question_mark = true;
4065 lexer.skip_token ();
4066 }
4067
35e4f3b4
JP
4068 // handle TypePath
4069 AST::TypePath type_path = parse_type_path ();
4070
4071 // handle closing parentheses
4072 if (has_parens)
4073 {
4074 if (!skip_token (RIGHT_PAREN))
4075 {
4076 return nullptr;
4077 }
4078 }
4079
4080 return std::unique_ptr<AST::TraitBound> (
4081 new AST::TraitBound (std::move (type_path), locus, has_parens,
4082 has_question_mark, std::move (for_lifetimes)));
4083}
4084
4085// Parses lifetime bounds.
4086template <typename ManagedTokenSource>
4087std::vector<AST::Lifetime>
4088Parser<ManagedTokenSource>::parse_lifetime_bounds ()
4089{
4090 std::vector<AST::Lifetime> lifetime_bounds;
4091
4092 while (true)
4093 {
827ceac9 4094 auto lifetime = parse_lifetime (false);
35e4f3b4
JP
4095
4096 // quick exit for parsing failure
827ceac9 4097 if (!lifetime)
35e4f3b4
JP
4098 break;
4099
827ceac9 4100 lifetime_bounds.push_back (std::move (lifetime.value ()));
35e4f3b4
JP
4101
4102 /* plus is maybe not allowed at end - spec defines it weirdly, so
4103 * assuming allowed at end */
4104 if (lexer.peek_token ()->get_id () != PLUS)
4105 break;
4106
4107 lexer.skip_token ();
4108 }
4109
4110 lifetime_bounds.shrink_to_fit ();
4111 return lifetime_bounds;
4112}
4113
4114// Parses lifetime bounds, with added check for ending token.
4115template <typename ManagedTokenSource>
4116template <typename EndTokenPred>
4117std::vector<AST::Lifetime>
4118Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token)
4119{
4120 std::vector<AST::Lifetime> lifetime_bounds;
4121
4122 while (!is_end_token (lexer.peek_token ()->get_id ()))
4123 {
827ceac9 4124 auto lifetime = parse_lifetime (false);
35e4f3b4 4125
827ceac9 4126 if (!lifetime)
35e4f3b4
JP
4127 {
4128 /* TODO: is it worth throwing away all lifetime bound info just
4129 * because one failed? */
4130 Error error (lexer.peek_token ()->get_locus (),
4131 "failed to parse lifetime in lifetime bounds");
4132 add_error (std::move (error));
4133
4134 return {};
4135 }
4136
827ceac9 4137 lifetime_bounds.push_back (std::move (lifetime.value ()));
35e4f3b4
JP
4138
4139 /* plus is maybe not allowed at end - spec defines it weirdly, so
4140 * assuming allowed at end */
4141 if (lexer.peek_token ()->get_id () != PLUS)
4142 break;
4143
4144 lexer.skip_token ();
4145 }
4146
4147 lifetime_bounds.shrink_to_fit ();
4148 return lifetime_bounds;
4149}
4150
4151/* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not
4152 * existing. */
4153template <typename ManagedTokenSource>
827ceac9 4154tl::expected<AST::Lifetime, ParseLifetimeError>
6def638e 4155Parser<ManagedTokenSource>::parse_lifetime (bool allow_elided)
35e4f3b4
JP
4156{
4157 const_TokenPtr lifetime_tok = lexer.peek_token ();
35e4f3b4
JP
4158 if (lifetime_tok->get_id () != LIFETIME)
4159 {
827ceac9
PEP
4160 if (allow_elided)
4161 {
4162 return AST::Lifetime::elided ();
4163 }
4164 else
4165 {
4166 return tl::make_unexpected<ParseLifetimeError> ({});
4167 }
35e4f3b4
JP
4168 }
4169 lexer.skip_token ();
4170
48408712
MJ
4171 return lifetime_from_token (lifetime_tok);
4172}
4173
4174template <typename ManagedTokenSource>
4175AST::Lifetime
4176Parser<ManagedTokenSource>::lifetime_from_token (const_TokenPtr tok)
4177{
d991a3f1 4178 location_t locus = tok->get_locus ();
48408712 4179 std::string lifetime_ident = tok->get_str ();
35e4f3b4 4180
c936a63c 4181 if (lifetime_ident == "static")
35e4f3b4
JP
4182 {
4183 return AST::Lifetime (AST::Lifetime::STATIC, "", locus);
4184 }
c936a63c 4185 else if (lifetime_ident == "_")
35e4f3b4 4186 {
50f30592 4187 // Explicitly and implicitly elided lifetimes follow the same rules.
35e4f3b4
JP
4188 return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus);
4189 }
4190 else
4191 {
4192 return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident),
4193 locus);
4194 }
4195}
4196
4679d129
PEP
4197template <typename ManagedTokenSource>
4198std::unique_ptr<AST::ExternalTypeItem>
4199Parser<ManagedTokenSource>::parse_external_type_item (AST::Visibility vis,
4200 AST::AttrVec outer_attrs)
4201{
d991a3f1 4202 location_t locus = lexer.peek_token ()->get_locus ();
4679d129
PEP
4203 skip_token (TYPE);
4204
4205 const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
4206 if (alias_name_tok == nullptr)
4207 {
4208 Error error (lexer.peek_token ()->get_locus (),
4209 "could not parse identifier in external opaque type");
4210 add_error (std::move (error));
4211
4212 skip_after_semicolon ();
4213 return nullptr;
4214 }
4215
4216 if (!skip_token (SEMICOLON))
4217 return nullptr;
4218
4219 return std::unique_ptr<AST::ExternalTypeItem> (
060652cd
PEP
4220 new AST::ExternalTypeItem (alias_name_tok->get_str (), std::move (vis),
4221 std::move (outer_attrs), std::move (locus)));
4679d129
PEP
4222}
4223
35e4f3b4
JP
4224// Parses a "type alias" (typedef) item.
4225template <typename ManagedTokenSource>
4226std::unique_ptr<AST::TypeAlias>
4227Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis,
4228 AST::AttrVec outer_attrs)
4229{
d991a3f1 4230 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
4231 skip_token (TYPE);
4232
4233 // TODO: use this token for identifier when finished that
4234 const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
4235 if (alias_name_tok == nullptr)
4236 {
4237 Error error (lexer.peek_token ()->get_locus (),
4238 "could not parse identifier in type alias");
4239 add_error (std::move (error));
4240
4241 skip_after_semicolon ();
4242 return nullptr;
4243 }
1c3a8fbb 4244 Identifier alias_name{alias_name_tok};
35e4f3b4
JP
4245
4246 // parse generic params, which may not exist
4247 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4248 = parse_generic_params_in_angles ();
4249
4250 // parse where clause, which may not exist
4251 AST::WhereClause where_clause = parse_where_clause ();
4252
4253 if (!skip_token (EQUAL))
4254 {
4255 skip_after_semicolon ();
4256 return nullptr;
4257 }
4258
4259 std::unique_ptr<AST::Type> type_to_alias = parse_type ();
4260
4261 if (!skip_token (SEMICOLON))
4262 {
4263 // should be skipping past this, not the next line
4264 return nullptr;
4265 }
4266
4267 return std::unique_ptr<AST::TypeAlias> (
4268 new AST::TypeAlias (std::move (alias_name), std::move (generic_params),
4269 std::move (where_clause), std::move (type_to_alias),
4270 std::move (vis), std::move (outer_attrs), locus));
4271}
4272
4273// Parse a struct item AST node.
4274template <typename ManagedTokenSource>
4275std::unique_ptr<AST::Struct>
4276Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis,
4277 AST::AttrVec outer_attrs)
4278{
4279 /* TODO: determine best way to parse the proper struct vs tuple struct -
4280 * share most of initial constructs so lookahead might be impossible, and if
4281 * not probably too expensive. Best way is probably unified parsing for the
4282 * initial parts and then pass them in as params to more derived functions.
4283 * Alternatively, just parse everything in this one function - do this if
4284 * function not too long. */
4285
4286 /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{'
4287 * struct_fields? '}' | ';' ) */
4288 /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')'
4289 * where_clause? ';' */
d991a3f1 4290 location_t locus = lexer.peek_token ()->get_locus ();
7f631967 4291 skip_token (STRUCT_KW);
35e4f3b4
JP
4292
4293 // parse struct name
4294 const_TokenPtr name_tok = expect_token (IDENTIFIER);
4295 if (name_tok == nullptr)
4296 {
4297 Error error (lexer.peek_token ()->get_locus (),
4298 "could not parse struct or tuple struct identifier");
4299 add_error (std::move (error));
4300
4301 // skip after somewhere?
4302 return nullptr;
4303 }
1c3a8fbb 4304 Identifier struct_name{name_tok};
35e4f3b4
JP
4305
4306 // parse generic params, which may or may not exist
4307 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4308 = parse_generic_params_in_angles ();
4309
4310 // branch on next token - determines whether proper struct or tuple struct
4311 if (lexer.peek_token ()->get_id () == LEFT_PAREN)
4312 {
4313 // tuple struct
4314
4315 // skip left parenthesis
4316 lexer.skip_token ();
4317
4318 // parse tuple fields
4319 std::vector<AST::TupleField> tuple_fields;
4320 // Might be empty tuple for unit tuple struct.
4321 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
4322 tuple_fields = std::vector<AST::TupleField> ();
4323 else
4324 tuple_fields = parse_tuple_fields ();
4325
4326 // tuple parameters must have closing parenthesis
4327 if (!skip_token (RIGHT_PAREN))
4328 {
4329 skip_after_semicolon ();
4330 return nullptr;
4331 }
4332
4333 // parse where clause, which is optional
4334 AST::WhereClause where_clause = parse_where_clause ();
4335
4336 if (!skip_token (SEMICOLON))
4337 {
4338 // can't skip after semicolon because it's meant to be here
4339 return nullptr;
4340 }
4341
4342 return std::unique_ptr<AST::TupleStruct> (
4343 new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name),
4344 std::move (generic_params),
4345 std::move (where_clause), std::move (vis),
4346 std::move (outer_attrs), locus));
4347 }
4348
4349 // assume it is a proper struct being parsed and continue outside of switch
4350 // - label only here to suppress warning
4351
4352 // parse where clause, which is optional
4353 AST::WhereClause where_clause = parse_where_clause ();
4354
4355 // branch on next token - determines whether struct is a unit struct
4356 const_TokenPtr t = lexer.peek_token ();
4357 switch (t->get_id ())
4358 {
4359 case LEFT_CURLY: {
4360 // struct with body
4361
4362 // skip curly bracket
4363 lexer.skip_token ();
4364
4365 // parse struct fields, if any
4366 std::vector<AST::StructField> struct_fields
4367 = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
4368
4369 if (!skip_token (RIGHT_CURLY))
4370 {
4371 // skip somewhere?
4372 return nullptr;
4373 }
4374
4375 return std::unique_ptr<AST::StructStruct> (new AST::StructStruct (
4376 std::move (struct_fields), std::move (struct_name),
4377 std::move (generic_params), std::move (where_clause), false,
4378 std::move (vis), std::move (outer_attrs), locus));
4379 }
4380 case SEMICOLON:
4381 // unit struct declaration
4382
4383 lexer.skip_token ();
4384
4385 return std::unique_ptr<AST::StructStruct> (
4386 new AST::StructStruct (std::move (struct_name),
4387 std::move (generic_params),
4388 std::move (where_clause), std::move (vis),
4389 std::move (outer_attrs), locus));
4390 default:
4391 add_error (Error (t->get_locus (),
4392 "unexpected token %qs in struct declaration",
4393 t->get_token_description ()));
4394
4395 // skip somewhere?
4396 return nullptr;
4397 }
4398}
4399
4400// Parses struct fields in struct declarations.
4401template <typename ManagedTokenSource>
4402std::vector<AST::StructField>
4403Parser<ManagedTokenSource>::parse_struct_fields ()
4404{
4405 std::vector<AST::StructField> fields;
4406
4407 AST::StructField initial_field = parse_struct_field ();
4408
4409 // Return empty field list if no field there
4410 if (initial_field.is_error ())
4411 return fields;
4412
4413 fields.push_back (std::move (initial_field));
4414
4415 while (lexer.peek_token ()->get_id () == COMMA)
4416 {
4417 lexer.skip_token ();
4418
4419 AST::StructField field = parse_struct_field ();
4420
4421 if (field.is_error ())
4422 {
4423 // would occur with trailing comma, so allowed
4424 break;
4425 }
4426
4427 fields.push_back (std::move (field));
4428 }
4429
4430 fields.shrink_to_fit ();
4431 return fields;
4432 // TODO: template if possible (parse_non_ptr_seq)
4433}
4434
4435// Parses struct fields in struct declarations.
4436template <typename ManagedTokenSource>
4437template <typename EndTokenPred>
4438std::vector<AST::StructField>
4439Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
4440{
4441 std::vector<AST::StructField> fields;
4442
4443 AST::StructField initial_field = parse_struct_field ();
4444
4445 // Return empty field list if no field there
4446 if (initial_field.is_error ())
4447 return fields;
4448
4449 fields.push_back (std::move (initial_field));
4450
4451 while (lexer.peek_token ()->get_id () == COMMA)
4452 {
4453 lexer.skip_token ();
4454
4455 if (is_end_tok (lexer.peek_token ()->get_id ()))
4456 break;
4457
4458 AST::StructField field = parse_struct_field ();
4459 if (field.is_error ())
4460 {
4461 /* TODO: should every field be ditched just because one couldn't be
4462 * parsed? */
4463 Error error (lexer.peek_token ()->get_locus (),
4464 "failed to parse struct field in struct fields");
4465 add_error (std::move (error));
4466
4467 return {};
4468 }
4469
4470 fields.push_back (std::move (field));
4471 }
4472
4473 fields.shrink_to_fit ();
4474 return fields;
4475 // TODO: template if possible (parse_non_ptr_seq)
4476}
4477
4478// Parses a single struct field (in a struct definition). Does not parse
4479// commas.
4480template <typename ManagedTokenSource>
4481AST::StructField
4482Parser<ManagedTokenSource>::parse_struct_field ()
4483{
4484 // parse outer attributes, if they exist
4485 AST::AttrVec outer_attrs = parse_outer_attributes ();
4486
4487 // parse visibility, if it exists
4488 AST::Visibility vis = parse_visibility ();
4489
d991a3f1 4490 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
4491
4492 // parse field name
4493 const_TokenPtr field_name_tok = lexer.peek_token ();
4494 if (field_name_tok->get_id () != IDENTIFIER)
4495 {
4496 // if not identifier, assumes there is no struct field and exits - not
4497 // necessarily error
4498 return AST::StructField::create_error ();
4499 }
1c3a8fbb 4500 Identifier field_name{field_name_tok};
35e4f3b4
JP
4501 lexer.skip_token ();
4502
4503 if (!skip_token (COLON))
4504 {
4505 // skip after somewhere?
4506 return AST::StructField::create_error ();
4507 }
4508
4509 // parse field type - this is required
4510 std::unique_ptr<AST::Type> field_type = parse_type ();
4511 if (field_type == nullptr)
4512 {
4513 Error error (lexer.peek_token ()->get_locus (),
4514 "could not parse type in struct field definition");
4515 add_error (std::move (error));
4516
4517 // skip after somewhere
4518 return AST::StructField::create_error ();
4519 }
4520
4521 return AST::StructField (std::move (field_name), std::move (field_type),
4522 std::move (vis), locus, std::move (outer_attrs));
4523}
4524
4525// Parses tuple fields in tuple/tuple struct declarations.
4526template <typename ManagedTokenSource>
4527std::vector<AST::TupleField>
4528Parser<ManagedTokenSource>::parse_tuple_fields ()
4529{
4530 std::vector<AST::TupleField> fields;
4531
4532 AST::TupleField initial_field = parse_tuple_field ();
4533
4534 // Return empty field list if no field there
4535 if (initial_field.is_error ())
4536 {
4537 return fields;
4538 }
4539
4540 fields.push_back (std::move (initial_field));
4541
4542 // maybe think of a better control structure here - do-while with an initial
4543 // error state? basically, loop through field list until can't find any more
4544 // params HACK: all current syntax uses of tuple fields have them ending
4545 // with a right paren token
4546 const_TokenPtr t = lexer.peek_token ();
4547 while (t->get_id () == COMMA)
4548 {
4549 // skip comma if applies - e.g. trailing comma
4550 lexer.skip_token ();
4551
4552 // break out due to right paren if it exists
4553 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
4554 {
4555 break;
4556 }
4557
4558 AST::TupleField field = parse_tuple_field ();
4559 if (field.is_error ())
4560 {
4561 Error error (lexer.peek_token ()->get_locus (),
4562 "failed to parse tuple field in tuple fields");
4563 add_error (std::move (error));
4564
4565 return std::vector<AST::TupleField> ();
4566 }
4567
4568 fields.push_back (std::move (field));
4569
4570 t = lexer.peek_token ();
4571 }
4572
4573 fields.shrink_to_fit ();
4574 return fields;
4575
4576 // TODO: this shares basically all code with function params and struct
4577 // fields
4578 // - templates?
4579}
4580
4581/* Parses a single tuple struct field in a tuple struct definition. Does not
4582 * parse commas. */
4583template <typename ManagedTokenSource>
4584AST::TupleField
4585Parser<ManagedTokenSource>::parse_tuple_field ()
4586{
4587 // parse outer attributes if they exist
4588 AST::AttrVec outer_attrs = parse_outer_attributes ();
4589
4590 // parse visibility if it exists
4591 AST::Visibility vis = parse_visibility ();
4592
d991a3f1 4593 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
4594
4595 // parse type, which is required
4596 std::unique_ptr<AST::Type> field_type = parse_type ();
4597 if (field_type == nullptr)
4598 {
4599 // error if null
4600 Error error (lexer.peek_token ()->get_locus (),
4601 "could not parse type in tuple struct field");
4602 add_error (std::move (error));
4603
4604 // skip after something
4605 return AST::TupleField::create_error ();
4606 }
4607
4608 return AST::TupleField (std::move (field_type), std::move (vis), locus,
4609 std::move (outer_attrs));
4610}
4611
4612// Parses a Rust "enum" tagged union item definition.
4613template <typename ManagedTokenSource>
4614std::unique_ptr<AST::Enum>
4615Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
4616 AST::AttrVec outer_attrs)
4617{
d991a3f1 4618 location_t locus = lexer.peek_token ()->get_locus ();
7f631967 4619 skip_token (ENUM_KW);
35e4f3b4
JP
4620
4621 // parse enum name
4622 const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
4623 if (enum_name_tok == nullptr)
4624 return nullptr;
4625
1c3a8fbb 4626 Identifier enum_name = {enum_name_tok};
35e4f3b4
JP
4627
4628 // parse generic params (of enum container, not enum variants) if they exist
4629 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4630 = parse_generic_params_in_angles ();
4631
4632 // parse where clause if it exists
4633 AST::WhereClause where_clause = parse_where_clause ();
4634
4635 if (!skip_token (LEFT_CURLY))
4636 {
4637 skip_after_end_block ();
4638 return nullptr;
4639 }
4640
4641 // parse actual enum variant definitions
4642 std::vector<std::unique_ptr<AST::EnumItem>> enum_items
4643 = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
4644
4645 if (!skip_token (RIGHT_CURLY))
4646 {
4647 skip_after_end_block ();
4648 return nullptr;
4649 }
4650
4651 return std::unique_ptr<AST::Enum> (
4652 new AST::Enum (std::move (enum_name), std::move (vis),
4653 std::move (generic_params), std::move (where_clause),
4654 std::move (enum_items), std::move (outer_attrs), locus));
4655}
4656
4657// Parses the enum variants inside an enum definiton.
4658template <typename ManagedTokenSource>
4659std::vector<std::unique_ptr<AST::EnumItem>>
4660Parser<ManagedTokenSource>::parse_enum_items ()
4661{
4662 std::vector<std::unique_ptr<AST::EnumItem>> items;
4663
4664 std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
4665
4666 // Return empty item list if no field there
4667 if (initial_item == nullptr)
4668 return items;
4669
4670 items.push_back (std::move (initial_item));
4671
4672 while (lexer.peek_token ()->get_id () == COMMA)
4673 {
4674 lexer.skip_token ();
4675
4676 std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
4677 if (item == nullptr)
4678 {
4679 // this would occur with a trailing comma, which is allowed
4680 break;
4681 }
4682
4683 items.push_back (std::move (item));
4684 }
4685
4686 items.shrink_to_fit ();
4687 return items;
4688
4689 /* TODO: use template if doable (parse_non_ptr_sequence) */
4690}
4691
4692// Parses the enum variants inside an enum definiton.
4693template <typename ManagedTokenSource>
4694template <typename EndTokenPred>
4695std::vector<std::unique_ptr<AST::EnumItem>>
4696Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
4697{
4698 std::vector<std::unique_ptr<AST::EnumItem>> items;
4699
4700 std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
4701
4702 // Return empty item list if no field there
4703 if (initial_item == nullptr)
4704 return items;
4705
4706 items.push_back (std::move (initial_item));
4707
4708 while (lexer.peek_token ()->get_id () == COMMA)
4709 {
4710 lexer.skip_token ();
4711
4712 if (is_end_tok (lexer.peek_token ()->get_id ()))
4713 break;
4714
4715 std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
4716 if (item == nullptr)
4717 {
4718 /* TODO should this ignore all successfully parsed enum items just
4719 * because one failed? */
4720 Error error (lexer.peek_token ()->get_locus (),
4721 "failed to parse enum item in enum items");
4722 add_error (std::move (error));
4723
4724 return {};
4725 }
4726
4727 items.push_back (std::move (item));
4728 }
4729
4730 items.shrink_to_fit ();
4731 return items;
4732
4733 /* TODO: use template if doable (parse_non_ptr_sequence) */
4734}
4735
4736/* Parses a single enum variant item in an enum definition. Does not parse
4737 * commas. */
4738template <typename ManagedTokenSource>
4739std::unique_ptr<AST::EnumItem>
4740Parser<ManagedTokenSource>::parse_enum_item ()
4741{
4742 // parse outer attributes if they exist
4743 AST::AttrVec outer_attrs = parse_outer_attributes ();
4744
4745 // parse visibility, which may or may not exist
4746 AST::Visibility vis = parse_visibility ();
4747
4748 // parse name for enum item, which is required
4749 const_TokenPtr item_name_tok = lexer.peek_token ();
4750 if (item_name_tok->get_id () != IDENTIFIER)
4751 {
4752 // this may not be an error but it means there is no enum item here
4753 return nullptr;
4754 }
4755 lexer.skip_token ();
1c3a8fbb 4756 Identifier item_name{item_name_tok};
35e4f3b4
JP
4757
4758 // branch based on next token
4759 const_TokenPtr t = lexer.peek_token ();
4760 switch (t->get_id ())
4761 {
4762 case LEFT_PAREN: {
4763 // tuple enum item
4764 lexer.skip_token ();
4765
4766 std::vector<AST::TupleField> tuple_fields;
4767 // Might be empty tuple for unit tuple enum variant.
4768 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
4769 tuple_fields = std::vector<AST::TupleField> ();
4770 else
4771 tuple_fields = parse_tuple_fields ();
4772
4773 if (!skip_token (RIGHT_PAREN))
4774 {
4775 // skip after somewhere
4776 return nullptr;
4777 }
4778
4779 return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
4780 std::move (item_name), std::move (vis), std::move (tuple_fields),
4781 std::move (outer_attrs), item_name_tok->get_locus ()));
4782 }
4783 case LEFT_CURLY: {
4784 // struct enum item
4785 lexer.skip_token ();
4786
4787 std::vector<AST::StructField> struct_fields
4788 = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
4789
4790 if (!skip_token (RIGHT_CURLY))
4791 {
4792 // skip after somewhere
4793 return nullptr;
4794 }
4795
4796 return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
4797 std::move (item_name), std::move (vis), std::move (struct_fields),
4798 std::move (outer_attrs), item_name_tok->get_locus ()));
4799 }
4800 case EQUAL: {
4801 // discriminant enum item
4802 lexer.skip_token ();
4803
4804 std::unique_ptr<AST::Expr> discriminant_expr = parse_expr ();
4805
4806 return std::unique_ptr<AST::EnumItemDiscriminant> (
4807 new AST::EnumItemDiscriminant (std::move (item_name), std::move (vis),
4808 std::move (discriminant_expr),
4809 std::move (outer_attrs),
4810 item_name_tok->get_locus ()));
4811 }
4812 default:
4813 // regular enum with just an identifier
4814 return std::unique_ptr<AST::EnumItem> (
4815 new AST::EnumItem (std::move (item_name), std::move (vis),
4816 std::move (outer_attrs),
4817 item_name_tok->get_locus ()));
4818 }
4819}
4820
4821// Parses a C-style (and C-compat) untagged union declaration.
4822template <typename ManagedTokenSource>
4823std::unique_ptr<AST::Union>
4824Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
4825 AST::AttrVec outer_attrs)
4826{
4827 /* hack - "weak keyword" by finding identifier called "union" (lookahead in
4828 * item switch) */
4829 const_TokenPtr union_keyword = expect_token (IDENTIFIER);
28652f21 4830 rust_assert (union_keyword->get_str () == Values::WeakKeywords::UNION);
d991a3f1 4831 location_t locus = union_keyword->get_locus ();
35e4f3b4
JP
4832
4833 // parse actual union name
4834 const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
4835 if (union_name_tok == nullptr)
4836 {
4837 skip_after_next_block ();
4838 return nullptr;
4839 }
1c3a8fbb 4840 Identifier union_name{union_name_tok};
35e4f3b4
JP
4841
4842 // parse optional generic parameters
4843 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4844 = parse_generic_params_in_angles ();
4845
4846 // parse optional where clause
4847 AST::WhereClause where_clause = parse_where_clause ();
4848
4849 if (!skip_token (LEFT_CURLY))
4850 {
4851 skip_after_end_block ();
4852 return nullptr;
4853 }
4854
4855 /* parse union inner items as "struct fields" because hey, syntax reuse.
4856 * Spec said so. */
4857 std::vector<AST::StructField> union_fields
4858 = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
4859
4860 if (!skip_token (RIGHT_CURLY))
4861 {
4862 // skip after somewhere
4863 return nullptr;
4864 }
4865
4866 return std::unique_ptr<AST::Union> (
4867 new AST::Union (std::move (union_name), std::move (vis),
4868 std::move (generic_params), std::move (where_clause),
4869 std::move (union_fields), std::move (outer_attrs), locus));
4870}
4871
4872/* Parses a "constant item" (compile-time constant to maybe "inline"
4873 * throughout the program - like constexpr). */
4874template <typename ManagedTokenSource>
4875std::unique_ptr<AST::ConstantItem>
4876Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
4877 AST::AttrVec outer_attrs)
4878{
d991a3f1 4879 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
4880 skip_token (CONST);
4881
4882 /* get constant identifier - this is either a proper identifier or the _
4883 * wildcard */
4884 const_TokenPtr ident_tok = lexer.peek_token ();
4885 // make default identifier the underscore wildcard one
f1c7ce7e 4886 std::string ident (Values::Keywords::UNDERSCORE);
35e4f3b4
JP
4887 switch (ident_tok->get_id ())
4888 {
4889 case IDENTIFIER:
4890 ident = ident_tok->get_str ();
4891 lexer.skip_token ();
4892 break;
4893 case UNDERSCORE:
4894 // do nothing - identifier is already "_"
4895 lexer.skip_token ();
4896 break;
4897 default:
4898 add_error (
4899 Error (ident_tok->get_locus (),
4900 "expected item name (identifier or %<_%>) in constant item "
4901 "declaration - found %qs",
4902 ident_tok->get_token_description ()));
4903
4904 skip_after_semicolon ();
4905 return nullptr;
4906 }
4907
4908 if (!skip_token (COLON))
4909 {
4910 skip_after_semicolon ();
4911 return nullptr;
4912 }
4913
4914 // parse constant type (required)
4915 std::unique_ptr<AST::Type> type = parse_type ();
4916
91732258
PEP
4917 // A const with no given expression value
4918 if (lexer.peek_token ()->get_id () == SEMICOLON)
4919 {
4920 lexer.skip_token ();
4921 return std::unique_ptr<AST::ConstantItem> (
4922 new AST::ConstantItem (std::move (ident), std::move (vis),
4923 std::move (type), std::move (outer_attrs),
4924 locus));
4925 }
4926
35e4f3b4
JP
4927 if (!skip_token (EQUAL))
4928 {
4929 skip_after_semicolon ();
4930 return nullptr;
4931 }
4932
4933 // parse constant expression (required)
4934 std::unique_ptr<AST::Expr> expr = parse_expr ();
4935
4936 if (!skip_token (SEMICOLON))
4937 {
4938 // skip somewhere?
4939 return nullptr;
4940 }
4941
4942 return std::unique_ptr<AST::ConstantItem> (
4943 new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
4944 std::move (expr), std::move (outer_attrs), locus));
4945}
4946
4947// Parses a "static item" (static storage item, with 'static lifetime).
4948template <typename ManagedTokenSource>
4949std::unique_ptr<AST::StaticItem>
4950Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
4951 AST::AttrVec outer_attrs)
4952{
d991a3f1 4953 location_t locus = lexer.peek_token ()->get_locus ();
7f631967 4954 skip_token (STATIC_KW);
35e4f3b4
JP
4955
4956 // determine whether static item is mutable
4957 bool is_mut = false;
4958 if (lexer.peek_token ()->get_id () == MUT)
4959 {
4960 is_mut = true;
4961 lexer.skip_token ();
4962 }
4963
4964 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4965 if (ident_tok == nullptr)
4966 return nullptr;
4967
1c3a8fbb 4968 Identifier ident{ident_tok};
35e4f3b4
JP
4969
4970 if (!skip_token (COLON))
4971 {
4972 skip_after_semicolon ();
4973 return nullptr;
4974 }
4975
4976 // parse static item type (required)
4977 std::unique_ptr<AST::Type> type = parse_type ();
4978
4979 if (!skip_token (EQUAL))
4980 {
4981 skip_after_semicolon ();
4982 return nullptr;
4983 }
4984
4985 // parse static item expression (required)
4986 std::unique_ptr<AST::Expr> expr = parse_expr ();
4987
4988 if (!skip_token (SEMICOLON))
4989 {
4990 // skip after somewhere
4991 return nullptr;
4992 }
4993
4994 return std::unique_ptr<AST::StaticItem> (
4995 new AST::StaticItem (std::move (ident), is_mut, std::move (type),
4996 std::move (expr), std::move (vis),
4997 std::move (outer_attrs), locus));
4998}
4999
5000// Parses a trait definition item, including unsafe ones.
5001template <typename ManagedTokenSource>
5002std::unique_ptr<AST::Trait>
5003Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
5004 AST::AttrVec outer_attrs)
5005{
d991a3f1 5006 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4 5007 bool is_unsafe = false;
22128105
AC
5008 bool is_auto_trait = false;
5009
35e4f3b4
JP
5010 if (lexer.peek_token ()->get_id () == UNSAFE)
5011 {
5012 is_unsafe = true;
5013 lexer.skip_token ();
5014 }
5015
22128105
AC
5016 if (lexer.peek_token ()->get_id () == AUTO)
5017 {
5018 is_auto_trait = true;
5019 lexer.skip_token ();
5020 }
5021
35e4f3b4
JP
5022 skip_token (TRAIT);
5023
5024 // parse trait name
5025 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5026 if (ident_tok == nullptr)
5027 return nullptr;
5028
1c3a8fbb 5029 Identifier ident{ident_tok};
35e4f3b4
JP
5030
5031 // parse generic parameters (if they exist)
5032 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5033 = parse_generic_params_in_angles ();
5034
5035 // create placeholder type param bounds in case they don't exist
5036 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
5037
5038 // parse type param bounds (if they exist)
5039 if (lexer.peek_token ()->get_id () == COLON)
5040 {
5041 lexer.skip_token ();
5042
5043 type_param_bounds = parse_type_param_bounds (
5044 [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
5045 // type_param_bounds = parse_type_param_bounds ();
5046 }
5047
5048 // parse where clause (if it exists)
5049 AST::WhereClause where_clause = parse_where_clause ();
5050
5051 if (!skip_token (LEFT_CURLY))
5052 {
5053 skip_after_end_block ();
5054 return nullptr;
5055 }
5056
5057 // parse inner attrs (if they exist)
5058 AST::AttrVec inner_attrs = parse_inner_attributes ();
5059
5060 // parse trait items
4287f316 5061 std::vector<std::unique_ptr<AST::AssociatedItem>> trait_items;
35e4f3b4
JP
5062
5063 const_TokenPtr t = lexer.peek_token ();
5064 while (t->get_id () != RIGHT_CURLY)
5065 {
4287f316 5066 std::unique_ptr<AST::AssociatedItem> trait_item = parse_trait_item ();
35e4f3b4
JP
5067
5068 if (trait_item == nullptr)
5069 {
5070 Error error (lexer.peek_token ()->get_locus (),
5071 "failed to parse trait item in trait");
5072 add_error (std::move (error));
5073
5074 return nullptr;
5075 }
5076 trait_items.push_back (std::move (trait_item));
5077
5078 t = lexer.peek_token ();
5079 }
5080
5081 if (!skip_token (RIGHT_CURLY))
5082 {
5083 // skip after something
5084 return nullptr;
5085 }
5086
5087 trait_items.shrink_to_fit ();
5088 return std::unique_ptr<AST::Trait> (
22128105
AC
5089 new AST::Trait (std::move (ident), is_unsafe, is_auto_trait,
5090 std::move (generic_params), std::move (type_param_bounds),
5091 std::move (where_clause), std::move (trait_items),
5092 std::move (vis), std::move (outer_attrs),
5093 std::move (inner_attrs), locus));
35e4f3b4
JP
5094}
5095
5096// Parses a trait item used inside traits (not trait, the Item).
5097template <typename ManagedTokenSource>
4287f316 5098std::unique_ptr<AST::AssociatedItem>
35e4f3b4
JP
5099Parser<ManagedTokenSource>::parse_trait_item ()
5100{
5101 // parse outer attributes (if they exist)
5102 AST::AttrVec outer_attrs = parse_outer_attributes ();
5103
ceed844b
PEP
5104 AST::Visibility vis = parse_visibility ();
5105
35e4f3b4
JP
5106 // lookahead to determine what type of trait item to parse
5107 const_TokenPtr tok = lexer.peek_token ();
5108 switch (tok->get_id ())
5109 {
af3f0482
KP
5110 case SUPER:
5111 case SELF:
5112 case CRATE:
5113 case DOLLAR_SIGN:
5114 // these seem to be SimplePath tokens, so this is a macro invocation
5115 // semi
5116 return parse_macro_invocation_semi (std::move (outer_attrs));
5117 case IDENTIFIER:
5118 if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
5119 return parse_function (std::move (vis), std::move (outer_attrs));
5120 else
5121 return parse_macro_invocation_semi (std::move (outer_attrs));
35e4f3b4 5122 case TYPE:
ceed844b 5123 return parse_trait_type (std::move (outer_attrs), vis);
35e4f3b4
JP
5124 case CONST:
5125 // disambiguate with function qualifier
5126 if (lexer.peek_token (1)->get_id () == IDENTIFIER)
5127 {
5128 return parse_trait_const (std::move (outer_attrs));
5129 }
5130 // else, fallthrough to function
5131 // TODO: find out how to disable gcc "implicit fallthrough" error
5132 gcc_fallthrough ();
f46fdb63 5133 case ASYNC:
35e4f3b4 5134 case UNSAFE:
7f631967 5135 case EXTERN_KW:
6e9dad6a
KP
5136 case FN_KW:
5137 return parse_function (std::move (vis), std::move (outer_attrs));
af3f0482
KP
5138 default:
5139 break;
35e4f3b4 5140 }
af3f0482
KP
5141 add_error (Error (tok->get_locus (),
5142 "unrecognised token %qs for item in trait",
5143 tok->get_token_description ()));
5144 // skip?
5145 return nullptr;
35e4f3b4
JP
5146}
5147
5148// Parse a typedef trait item.
5149template <typename ManagedTokenSource>
5150std::unique_ptr<AST::TraitItemType>
ceed844b
PEP
5151Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs,
5152 AST::Visibility vis)
35e4f3b4 5153{
d991a3f1 5154 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
5155 skip_token (TYPE);
5156
5157 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5158 if (ident_tok == nullptr)
5159 return nullptr;
5160
1c3a8fbb 5161 Identifier ident{ident_tok};
35e4f3b4
JP
5162
5163 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
5164
5165 // parse optional colon
5166 if (lexer.peek_token ()->get_id () == COLON)
5167 {
5168 lexer.skip_token ();
5169
5170 // parse optional type param bounds
5171 bounds
5172 = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
5173 // bounds = parse_type_param_bounds ();
5174 }
5175
5176 if (!skip_token (SEMICOLON))
5177 {
5178 // skip?
5179 return nullptr;
5180 }
5181
5182 return std::unique_ptr<AST::TraitItemType> (
5183 new AST::TraitItemType (std::move (ident), std::move (bounds),
ceed844b 5184 std::move (outer_attrs), vis, locus));
35e4f3b4
JP
5185}
5186
5187// Parses a constant trait item.
5188template <typename ManagedTokenSource>
5189std::unique_ptr<AST::TraitItemConst>
5190Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
5191{
d991a3f1 5192 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
5193 skip_token (CONST);
5194
5195 // parse constant item name
5196 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5197 if (ident_tok == nullptr)
5198 return nullptr;
5199
1c3a8fbb 5200 Identifier ident{ident_tok};
35e4f3b4
JP
5201
5202 if (!skip_token (COLON))
5203 {
5204 skip_after_semicolon ();
5205 return nullptr;
5206 }
5207
5208 // parse constant trait item type
5209 std::unique_ptr<AST::Type> type = parse_type ();
5210
5211 // parse constant trait body expression, if it exists
5212 std::unique_ptr<AST::Expr> const_body = nullptr;
5213 if (lexer.peek_token ()->get_id () == EQUAL)
5214 {
5215 lexer.skip_token ();
5216
5217 // expression must exist, so parse it
5218 const_body = parse_expr ();
5219 }
5220
5221 if (!skip_token (SEMICOLON))
5222 {
5223 // skip after something?
5224 return nullptr;
5225 }
5226
5227 return std::unique_ptr<AST::TraitItemConst> (
5228 new AST::TraitItemConst (std::move (ident), std::move (type),
5229 std::move (const_body), std::move (outer_attrs),
5230 locus));
5231}
5232
5233/* Parses a struct "impl" item (both inherent impl and trait impl can be
5234 * parsed here), */
5235template <typename ManagedTokenSource>
5236std::unique_ptr<AST::Impl>
5237Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
5238 AST::AttrVec outer_attrs)
5239{
5240 /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
5241 * must be a trait impl. However, this isn't enough for full disambiguation,
5242 * so don't branch here. */
d991a3f1 5243 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
5244 bool is_unsafe = false;
5245 if (lexer.peek_token ()->get_id () == UNSAFE)
5246 {
5247 lexer.skip_token ();
5248 is_unsafe = true;
5249 }
5250
5251 if (!skip_token (IMPL))
5252 {
5253 skip_after_next_block ();
5254 return nullptr;
5255 }
5256
5257 // parse generic params (shared by trait and inherent impls)
5258 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5259 = parse_generic_params_in_angles ();
5260
5261 // Again, trait impl-only feature, but optional one, so can be used for
5262 // branching yet.
5263 bool has_exclam = false;
5264 if (lexer.peek_token ()->get_id () == EXCLAM)
5265 {
5266 lexer.skip_token ();
5267 has_exclam = true;
5268 }
5269
5270 /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
5271 * doesn't parse too much and not work. */
5272 AST::TypePath type_path = parse_type_path ();
5273 if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
5274 {
5275 /* cannot parse type path (or not for token next, at least), so must be
5276 * inherent impl */
5277
5278 // hacky conversion of TypePath stack object to Type pointer
5279 std::unique_ptr<AST::Type> type = nullptr;
5280 if (!type_path.is_error ())
5281 type = std::unique_ptr<AST::TypePath> (
5282 new AST::TypePath (std::move (type_path)));
5283 else
5284 type = parse_type ();
5285
5286 // Type is required, so error if null
5287 if (type == nullptr)
5288 {
5289 Error error (lexer.peek_token ()->get_locus (),
5290 "could not parse type in inherent impl");
5291 add_error (std::move (error));
5292
5293 skip_after_next_block ();
5294 return nullptr;
5295 }
5296
5297 // parse optional where clause
5298 AST::WhereClause where_clause = parse_where_clause ();
5299
5300 if (!skip_token (LEFT_CURLY))
5301 {
5302 // TODO: does this still skip properly?
5303 skip_after_end_block ();
5304 return nullptr;
5305 }
5306
5307 // parse inner attributes (optional)
5308 AST::AttrVec inner_attrs = parse_inner_attributes ();
5309
5310 // parse inherent impl items
f84e5642 5311 std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
35e4f3b4
JP
5312
5313 const_TokenPtr t = lexer.peek_token ();
5314 while (t->get_id () != RIGHT_CURLY)
5315 {
f84e5642 5316 std::unique_ptr<AST::AssociatedItem> impl_item
35e4f3b4
JP
5317 = parse_inherent_impl_item ();
5318
5319 if (impl_item == nullptr)
5320 {
5321 Error error (
5322 lexer.peek_token ()->get_locus (),
5323 "failed to parse inherent impl item in inherent impl");
5324 add_error (std::move (error));
5325
5326 return nullptr;
5327 }
5328
5329 impl_items.push_back (std::move (impl_item));
5330
5331 t = lexer.peek_token ();
5332 }
5333
5334 if (!skip_token (RIGHT_CURLY))
5335 {
5336 // skip somewhere
5337 return nullptr;
5338 }
5339
5340 // DEBUG
5341 rust_debug ("successfully parsed inherent impl");
5342
5343 impl_items.shrink_to_fit ();
5344
5345 return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
5346 std::move (impl_items), std::move (generic_params), std::move (type),
5347 std::move (where_clause), std::move (vis), std::move (inner_attrs),
5348 std::move (outer_attrs), locus));
5349 }
5350 else
5351 {
5352 // type path must both be valid and next token is for, so trait impl
5353 if (!skip_token (FOR))
5354 {
5355 skip_after_next_block ();
5356 return nullptr;
5357 }
5358
5359 // parse type
5360 std::unique_ptr<AST::Type> type = parse_type ();
5361 // ensure type is included as it is required
5362 if (type == nullptr)
5363 {
5364 Error error (lexer.peek_token ()->get_locus (),
5365 "could not parse type in trait impl");
5366 add_error (std::move (error));
5367
5368 skip_after_next_block ();
5369 return nullptr;
5370 }
5371
5372 // parse optional where clause
5373 AST::WhereClause where_clause = parse_where_clause ();
5374
5375 if (!skip_token (LEFT_CURLY))
5376 {
5377 // TODO: does this still skip properly?
5378 skip_after_end_block ();
5379 return nullptr;
5380 }
5381
5382 // parse inner attributes (optional)
5383 AST::AttrVec inner_attrs = parse_inner_attributes ();
5384
5385 // parse trait impl items
1740fbe1 5386 std::vector<std::unique_ptr<AST::AssociatedItem>> impl_items;
35e4f3b4
JP
5387
5388 const_TokenPtr t = lexer.peek_token ();
5389 while (t->get_id () != RIGHT_CURLY)
5390 {
1740fbe1 5391 std::unique_ptr<AST::AssociatedItem> impl_item
35e4f3b4
JP
5392 = parse_trait_impl_item ();
5393
5394 if (impl_item == nullptr)
5395 {
5396 Error error (lexer.peek_token ()->get_locus (),
5397 "failed to parse trait impl item in trait impl");
5398 add_error (std::move (error));
5399
5400 return nullptr;
5401 }
5402
5403 impl_items.push_back (std::move (impl_item));
5404
5405 t = lexer.peek_token ();
5406
5407 // DEBUG
5408 rust_debug ("successfully parsed a trait impl item");
5409 }
5410 // DEBUG
5411 rust_debug ("successfully finished trait impl items");
5412
5413 if (!skip_token (RIGHT_CURLY))
5414 {
5415 // skip somewhere
5416 return nullptr;
5417 }
5418
5419 // DEBUG
5420 rust_debug ("successfully parsed trait impl");
5421
5422 impl_items.shrink_to_fit ();
5423
5424 return std::unique_ptr<AST::TraitImpl> (
5425 new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
5426 std::move (impl_items), std::move (generic_params),
5427 std::move (type), std::move (where_clause),
5428 std::move (vis), std::move (inner_attrs),
5429 std::move (outer_attrs), locus));
5430 }
5431}
5432
5433// Parses a single inherent impl item (item inside an inherent impl block).
5434template <typename ManagedTokenSource>
f84e5642 5435std::unique_ptr<AST::AssociatedItem>
35e4f3b4
JP
5436Parser<ManagedTokenSource>::parse_inherent_impl_item ()
5437{
5438 // parse outer attributes (if they exist)
5439 AST::AttrVec outer_attrs = parse_outer_attributes ();
5440
5441 // TODO: cleanup - currently an unreadable mess
5442
5443 // branch on next token:
5444 const_TokenPtr t = lexer.peek_token ();
5445 switch (t->get_id ())
5446 {
5447 case IDENTIFIER:
5448 // FIXME: Arthur: Do we need to some lookahead here?
5449 return parse_macro_invocation_semi (outer_attrs);
5450 case SUPER:
5451 case SELF:
5452 case CRATE:
5453 case PUB: {
5454 // visibility, so not a macro invocation semi - must be constant,
5455 // function, or method
5456 AST::Visibility vis = parse_visibility ();
5457
5458 // TODO: is a recursive call to parse_inherent_impl_item better?
5459 switch (lexer.peek_token ()->get_id ())
5460 {
7f631967 5461 case EXTERN_KW:
35e4f3b4 5462 case UNSAFE:
7f631967 5463 case FN_KW:
35e4f3b4
JP
5464 // function or method
5465 return parse_inherent_impl_function_or_method (std::move (vis),
5466 std::move (
5467 outer_attrs));
5468 case CONST:
5469 // lookahead to resolve production - could be function/method or
5470 // const item
5471 t = lexer.peek_token (1);
5472
5473 switch (t->get_id ())
5474 {
5475 case IDENTIFIER:
5476 case UNDERSCORE:
5477 return parse_const_item (std::move (vis),
5478 std::move (outer_attrs));
5479 case UNSAFE:
7f631967
PEP
5480 case EXTERN_KW:
5481 case FN_KW:
35e4f3b4
JP
5482 return parse_inherent_impl_function_or_method (std::move (vis),
5483 std::move (
5484 outer_attrs));
5485 default:
5486 add_error (Error (t->get_locus (),
5487 "unexpected token %qs in some sort of const "
5488 "item in inherent impl",
5489 t->get_token_description ()));
5490
5491 lexer.skip_token (1); // TODO: is this right thing to do?
5492 return nullptr;
5493 }
5494 default:
5495 add_error (
5496 Error (t->get_locus (),
5497 "unrecognised token %qs for item in inherent impl",
5498 t->get_token_description ()));
5499 // skip?
5500 return nullptr;
5501 }
5502 }
7a0c487d 5503 case ASYNC:
7f631967 5504 case EXTERN_KW:
35e4f3b4 5505 case UNSAFE:
7f631967 5506 case FN_KW:
35e4f3b4
JP
5507 // function or method
5508 return parse_inherent_impl_function_or_method (
5509 AST::Visibility::create_private (), std::move (outer_attrs));
5510 case CONST:
5511 /* lookahead to resolve production - could be function/method or const
5512 * item */
5513 t = lexer.peek_token (1);
5514
5515 switch (t->get_id ())
5516 {
5517 case IDENTIFIER:
5518 case UNDERSCORE:
5519 return parse_const_item (AST::Visibility::create_private (),
5520 std::move (outer_attrs));
5521 case UNSAFE:
7f631967
PEP
5522 case EXTERN_KW:
5523 case FN_KW:
35e4f3b4
JP
5524 return parse_inherent_impl_function_or_method (
5525 AST::Visibility::create_private (), std::move (outer_attrs));
5526 default:
5527 add_error (Error (t->get_locus (),
5528 "unexpected token %qs in some sort of const item "
5529 "in inherent impl",
5530 t->get_token_description ()));
5531
5532 lexer.skip_token (1); // TODO: is this right thing to do?
5533 return nullptr;
5534 }
93866b6a 5535 rust_unreachable ();
35e4f3b4
JP
5536 default:
5537 add_error (Error (t->get_locus (),
5538 "unrecognised token %qs for item in inherent impl",
5539 t->get_token_description ()));
5540
5541 // skip?
5542 return nullptr;
5543 }
5544}
5545
5546/* For internal use only by parse_inherent_impl_item() - splits giant method
5547 * into smaller ones and prevents duplication of logic. Strictly, this parses
5548 * a function or method item inside an inherent impl item block. */
5549// TODO: make this a templated function with "return type" as type param -
5550// InherentImplItem is this specialisation of the template while TraitImplItem
5551// will be the other.
5552template <typename ManagedTokenSource>
f84e5642 5553std::unique_ptr<AST::AssociatedItem>
35e4f3b4
JP
5554Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
5555 AST::Visibility vis, AST::AttrVec outer_attrs)
5556{
d991a3f1 5557 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
5558 // parse function or method qualifiers
5559 AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
5560
7f631967 5561 skip_token (FN_KW);
35e4f3b4
JP
5562
5563 // parse function or method name
5564 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5565 if (ident_tok == nullptr)
5566 return nullptr;
5567
1c3a8fbb 5568 Identifier ident{ident_tok};
35e4f3b4
JP
5569
5570 // parse generic params
5571 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5572 = parse_generic_params_in_angles ();
5573
5574 if (!skip_token (LEFT_PAREN))
5575 {
5576 // skip after somewhere?
5577 return nullptr;
5578 }
5579
5580 // now for function vs method disambiguation - method has opening "self"
5581 // param
3e450ae1
PEP
5582 auto initial_param = parse_self_param ();
5583
5584 if (!initial_param.has_value () && initial_param.error () != NOT_SELF)
5585 return nullptr;
5586
35e4f3b4
JP
5587 /* FIXME: ensure that self param doesn't accidently consume tokens for a
5588 * function one idea is to lookahead up to 4 tokens to see whether self is
5589 * one of them */
5590 bool is_method = false;
3e450ae1 5591 if (initial_param.has_value ())
35e4f3b4 5592 {
3e450ae1 5593 if ((*initial_param)->is_self ())
513b0154 5594 is_method = true;
35e4f3b4
JP
5595
5596 /* skip comma so function and method regular params can be parsed in
5597 * same way */
5598 if (lexer.peek_token ()->get_id () == COMMA)
5599 lexer.skip_token ();
5600 }
5601
5602 // parse trait function params
513b0154 5603 std::vector<std::unique_ptr<AST::Param>> function_params
35e4f3b4
JP
5604 = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
5605
3e450ae1 5606 if (initial_param.has_value ())
513b0154 5607 function_params.insert (function_params.begin (),
3e450ae1 5608 std::move (*initial_param));
513b0154 5609
35e4f3b4
JP
5610 if (!skip_token (RIGHT_PAREN))
5611 {
5612 skip_after_end_block ();
5613 return nullptr;
5614 }
5615
5616 // parse return type (optional)
5617 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
5618
5619 // parse where clause (optional)
5620 AST::WhereClause where_clause = parse_where_clause ();
5621
7a989394 5622 tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
35e4f3b4 5623 if (lexer.peek_token ()->get_id () == SEMICOLON)
7a989394
PEP
5624 lexer.skip_token ();
5625 else
35e4f3b4 5626 {
7a989394 5627 auto result = parse_block_expr ();
35e4f3b4 5628
7a989394
PEP
5629 if (result == nullptr)
5630 {
5631 Error error (
5632 lexer.peek_token ()->get_locus (),
5633 "could not parse definition in inherent impl %s definition",
5634 is_method ? "method" : "function");
5635 add_error (std::move (error));
35e4f3b4 5636
7a989394
PEP
5637 skip_after_end_block ();
5638 return nullptr;
5639 }
5640 body = std::move (result);
35e4f3b4
JP
5641 }
5642
7a989394
PEP
5643 return std::unique_ptr<AST::Function> (
5644 new AST::Function (std::move (ident), std::move (qualifiers),
5645 std::move (generic_params), std::move (function_params),
5646 std::move (return_type), std::move (where_clause),
5647 std::move (body), std::move (vis),
5648 std::move (outer_attrs), locus));
35e4f3b4
JP
5649}
5650
5651// Parses a single trait impl item (item inside a trait impl block).
5652template <typename ManagedTokenSource>
1740fbe1 5653std::unique_ptr<AST::AssociatedItem>
35e4f3b4
JP
5654Parser<ManagedTokenSource>::parse_trait_impl_item ()
5655{
5656 // parse outer attributes (if they exist)
5657 AST::AttrVec outer_attrs = parse_outer_attributes ();
5658
73b6d9b9
AC
5659 auto visibility = AST::Visibility::create_private ();
5660 if (lexer.peek_token ()->get_id () == PUB)
5661 visibility = parse_visibility ();
35e4f3b4
JP
5662
5663 // branch on next token:
5664 const_TokenPtr t = lexer.peek_token ();
5665 switch (t->get_id ())
5666 {
35e4f3b4
JP
5667 case SUPER:
5668 case SELF:
5669 case CRATE:
5670 case DOLLAR_SIGN:
5671 // these seem to be SimplePath tokens, so this is a macro invocation
5672 // semi
5673 return parse_macro_invocation_semi (std::move (outer_attrs));
73b6d9b9 5674 case IDENTIFIER:
28652f21 5675 if (lexer.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT)
73b6d9b9
AC
5676 return parse_trait_impl_function_or_method (visibility,
5677 std::move (outer_attrs));
5678 else
5679 return parse_macro_invocation_semi (std::move (outer_attrs));
35e4f3b4 5680 case TYPE:
73b6d9b9 5681 return parse_type_alias (visibility, std::move (outer_attrs));
7f631967 5682 case EXTERN_KW:
35e4f3b4 5683 case UNSAFE:
7f631967 5684 case FN_KW:
35e4f3b4 5685 // function or method
73b6d9b9
AC
5686 return parse_trait_impl_function_or_method (visibility,
5687 std::move (outer_attrs));
bffceda8
KP
5688 case ASYNC:
5689 return parse_async_item (visibility, std::move (outer_attrs));
35e4f3b4
JP
5690 case CONST:
5691 // lookahead to resolve production - could be function/method or const
5692 // item
5693 t = lexer.peek_token (1);
5694
5695 switch (t->get_id ())
5696 {
5697 case IDENTIFIER:
5698 case UNDERSCORE:
73b6d9b9 5699 return parse_const_item (visibility, std::move (outer_attrs));
35e4f3b4 5700 case UNSAFE:
7f631967
PEP
5701 case EXTERN_KW:
5702 case FN_KW:
73b6d9b9
AC
5703 return parse_trait_impl_function_or_method (visibility,
5704 std::move (outer_attrs));
35e4f3b4
JP
5705 default:
5706 add_error (Error (
5707 t->get_locus (),
5708 "unexpected token %qs in some sort of const item in trait impl",
5709 t->get_token_description ()));
5710
5711 lexer.skip_token (1); // TODO: is this right thing to do?
5712 return nullptr;
5713 }
93866b6a 5714 rust_unreachable ();
35e4f3b4 5715 default:
73b6d9b9 5716 break;
35e4f3b4 5717 }
73b6d9b9
AC
5718 add_error (Error (t->get_locus (),
5719 "unrecognised token %qs for item in trait impl",
5720 t->get_token_description ()));
5721
5722 // skip?
5723 return nullptr;
35e4f3b4
JP
5724}
5725
5726/* For internal use only by parse_trait_impl_item() - splits giant method into
5727 * smaller ones and prevents duplication of logic. Strictly, this parses a
5728 * function or method item inside a trait impl item block. */
5729template <typename ManagedTokenSource>
1740fbe1 5730std::unique_ptr<AST::AssociatedItem>
35e4f3b4
JP
5731Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
5732 AST::Visibility vis, AST::AttrVec outer_attrs)
5733{
5734 // this shares virtually all logic with
5735 // parse_inherent_impl_function_or_method
5736 // - template?
d991a3f1 5737 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4 5738
73b6d9b9
AC
5739 auto is_default = false;
5740 auto t = lexer.peek_token ();
28652f21
PEP
5741 if (t->get_id () == IDENTIFIER
5742 && t->get_str () == Values::WeakKeywords::DEFAULT)
73b6d9b9
AC
5743 {
5744 is_default = true;
5745 lexer.skip_token ();
5746 }
5747
af874e4b
OA
5748 // parse function or method qualifiers
5749 AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
5750
7f631967 5751 skip_token (FN_KW);
35e4f3b4
JP
5752
5753 // parse function or method name
5754 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5755 if (ident_tok == nullptr)
5756 {
5757 return nullptr;
5758 }
1c3a8fbb 5759 Identifier ident{ident_tok};
35e4f3b4
JP
5760
5761 // DEBUG:
5762 rust_debug (
5763 "about to start parsing generic params in trait impl function or method");
5764
5765 // parse generic params
5766 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5767 = parse_generic_params_in_angles ();
5768
5769 // DEBUG:
5770 rust_debug (
5771 "finished parsing generic params in trait impl function or method");
5772
5773 if (!skip_token (LEFT_PAREN))
5774 {
5775 // skip after somewhere?
5776 return nullptr;
5777 }
5778
5779 // now for function vs method disambiguation - method has opening "self"
5780 // param
3e450ae1
PEP
5781 auto initial_param = parse_self_param ();
5782
5783 if (!initial_param.has_value () && initial_param.error () != NOT_SELF)
5784 return nullptr;
5785
35e4f3b4
JP
5786 // FIXME: ensure that self param doesn't accidently consume tokens for a
5787 // function
5788 bool is_method = false;
3e450ae1 5789 if (initial_param.has_value ())
35e4f3b4 5790 {
3e450ae1 5791 if ((*initial_param)->is_self ())
513b0154 5792 is_method = true;
35e4f3b4
JP
5793
5794 // skip comma so function and method regular params can be parsed in
5795 // same way
5796 if (lexer.peek_token ()->get_id () == COMMA)
5797 {
5798 lexer.skip_token ();
5799 }
5800
5801 // DEBUG
5802 rust_debug ("successfully parsed self param in method trait impl item");
5803 }
5804
5805 // DEBUG
5806 rust_debug (
5807 "started to parse function params in function or method trait impl item");
5808
5809 // parse trait function params (only if next token isn't right paren)
513b0154 5810 std::vector<std::unique_ptr<AST::Param>> function_params;
35e4f3b4
JP
5811 if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
5812 {
5813 function_params
5814 = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
5815
5816 if (function_params.empty ())
5817 {
5818 Error error (
5819 lexer.peek_token ()->get_locus (),
5820 "failed to parse function params in trait impl %s definition",
5821 is_method ? "method" : "function");
5822 add_error (std::move (error));
5823
5824 skip_after_next_block ();
5825 return nullptr;
5826 }
5827 }
5828
3e450ae1 5829 if (initial_param.has_value ())
513b0154 5830 function_params.insert (function_params.begin (),
3e450ae1 5831 std::move (*initial_param));
513b0154 5832
35e4f3b4
JP
5833 // DEBUG
5834 rust_debug ("successfully parsed function params in function or method "
5835 "trait impl item");
5836
5837 if (!skip_token (RIGHT_PAREN))
5838 {
5839 skip_after_next_block ();
5840 return nullptr;
5841 }
5842
5843 // parse return type (optional)
5844 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
5845
5846 // DEBUG
5847 rust_debug (
5848 "successfully parsed return type in function or method trait impl item");
5849
5850 // parse where clause (optional)
5851 AST::WhereClause where_clause = parse_where_clause ();
5852
5853 // DEBUG
5854 rust_debug (
5855 "successfully parsed where clause in function or method trait impl item");
5856
5857 // parse function definition (in block) - semicolon not allowed
7a989394 5858 tl::optional<std::unique_ptr<AST::BlockExpr>> body = tl::nullopt;
35e4f3b4 5859
7a989394
PEP
5860 if (lexer.peek_token ()->get_id () == SEMICOLON)
5861 lexer.skip_token ();
5862 else
35e4f3b4 5863 {
7a989394
PEP
5864 auto result = parse_block_expr ();
5865 if (result == nullptr)
5866 {
5867 Error error (lexer.peek_token ()->get_locus (),
5868 "could not parse definition in trait impl %s definition",
5869 is_method ? "method" : "function");
5870 add_error (std::move (error));
35e4f3b4 5871
7a989394
PEP
5872 skip_after_end_block ();
5873 return nullptr;
5874 }
5875 body = std::move (result);
35e4f3b4
JP
5876 }
5877
513b0154
PEP
5878 return std::unique_ptr<AST::Function> (
5879 new AST::Function (std::move (ident), std::move (qualifiers),
5880 std::move (generic_params), std::move (function_params),
5881 std::move (return_type), std::move (where_clause),
5882 std::move (body), std::move (vis),
5883 std::move (outer_attrs), locus, is_default));
35e4f3b4
JP
5884}
5885
5886// Parses an extern block of declarations.
5887template <typename ManagedTokenSource>
5888std::unique_ptr<AST::ExternBlock>
5889Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
5890 AST::AttrVec outer_attrs)
5891{
d991a3f1 5892 location_t locus = lexer.peek_token ()->get_locus ();
7f631967 5893 skip_token (EXTERN_KW);
35e4f3b4
JP
5894
5895 // detect optional abi name
5896 std::string abi;
5897 const_TokenPtr next_tok = lexer.peek_token ();
5898 if (next_tok->get_id () == STRING_LITERAL)
5899 {
5900 lexer.skip_token ();
5901 abi = next_tok->get_str ();
5902 }
5903
5904 if (!skip_token (LEFT_CURLY))
5905 {
5906 skip_after_end_block ();
5907 return nullptr;
5908 }
5909
5910 AST::AttrVec inner_attrs = parse_inner_attributes ();
5911
5912 // parse declarations inside extern block
5913 std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
5914
5915 const_TokenPtr t = lexer.peek_token ();
5916 while (t->get_id () != RIGHT_CURLY)
5917 {
5918 std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
5919
5920 if (extern_item == nullptr)
5921 {
5922 Error error (t->get_locus (),
5923 "failed to parse external item despite not reaching "
5924 "end of extern block");
5925 add_error (std::move (error));
5926
5927 return nullptr;
5928 }
5929
5930 extern_items.push_back (std::move (extern_item));
5931
5932 t = lexer.peek_token ();
5933 }
5934
5935 if (!skip_token (RIGHT_CURLY))
5936 {
5937 // skip somewhere
5938 return nullptr;
5939 }
5940
5941 extern_items.shrink_to_fit ();
5942
5943 return std::unique_ptr<AST::ExternBlock> (
5944 new AST::ExternBlock (std::move (abi), std::move (extern_items),
5945 std::move (vis), std::move (inner_attrs),
5946 std::move (outer_attrs), locus));
5947}
5948
5949// Parses a single extern block item (static or function declaration).
5950template <typename ManagedTokenSource>
5951std::unique_ptr<AST::ExternalItem>
5952Parser<ManagedTokenSource>::parse_external_item ()
5953{
5954 // parse optional outer attributes
5955 AST::AttrVec outer_attrs = parse_outer_attributes ();
5956
d991a3f1 5957 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
5958
5959 // parse optional visibility
5960 AST::Visibility vis = parse_visibility ();
5961
5962 const_TokenPtr t = lexer.peek_token ();
5963 switch (t->get_id ())
5964 {
5965 case IDENTIFIER:
5966 return parse_macro_invocation_semi (outer_attrs);
7f631967 5967 case STATIC_KW: {
35e4f3b4
JP
5968 // parse extern static item
5969 lexer.skip_token ();
5970
5971 // parse mut (optional)
5972 bool has_mut = false;
5973 if (lexer.peek_token ()->get_id () == MUT)
5974 {
5975 lexer.skip_token ();
5976 has_mut = true;
5977 }
5978
5979 // parse identifier
5980 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5981 if (ident_tok == nullptr)
5982 {
5983 skip_after_semicolon ();
5984 return nullptr;
5985 }
1c3a8fbb 5986 Identifier ident{ident_tok};
35e4f3b4
JP
5987
5988 if (!skip_token (COLON))
5989 {
5990 skip_after_semicolon ();
5991 return nullptr;
5992 }
5993
5994 // parse type (required)
5995 std::unique_ptr<AST::Type> type = parse_type ();
5996 if (type == nullptr)
5997 {
5998 Error error (lexer.peek_token ()->get_locus (),
5999 "failed to parse type in external static item");
6000 add_error (std::move (error));
6001
6002 skip_after_semicolon ();
6003 return nullptr;
6004 }
6005
6006 if (!skip_token (SEMICOLON))
6007 {
6008 // skip after somewhere?
6009 return nullptr;
6010 }
6011
6012 return std::unique_ptr<AST::ExternalStaticItem> (
6013 new AST::ExternalStaticItem (std::move (ident), std::move (type),
6014 has_mut, std::move (vis),
6015 std::move (outer_attrs), locus));
6016 }
7f631967 6017 case FN_KW:
293ac1ba 6018 return parse_function (std::move (vis), std::move (outer_attrs), true);
bbc1dfcc 6019
4679d129
PEP
6020 case TYPE:
6021 return parse_external_type_item (std::move (vis),
6022 std::move (outer_attrs));
35e4f3b4
JP
6023 default:
6024 // error
6025 add_error (
6026 Error (t->get_locus (),
6027 "unrecognised token %qs in extern block item declaration",
6028 t->get_token_description ()));
6029
6030 skip_after_semicolon ();
6031 return nullptr;
6032 }
6033}
6034
35e4f3b4
JP
6035// Parses a statement (will further disambiguate any statement).
6036template <typename ManagedTokenSource>
6037std::unique_ptr<AST::Stmt>
6038Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
6039{
6040 // quick exit for empty statement
6041 // FIXME: Can we have empty statements without semicolons? Just nothing?
6042 const_TokenPtr t = lexer.peek_token ();
6043 if (t->get_id () == SEMICOLON)
6044 {
6045 lexer.skip_token ();
6046 return std::unique_ptr<AST::EmptyStmt> (
6047 new AST::EmptyStmt (t->get_locus ()));
6048 }
6049
6050 // parse outer attributes
6051 AST::AttrVec outer_attrs = parse_outer_attributes ();
6052
6053 // parsing this will be annoying because of the many different possibilities
6054 /* best may be just to copy paste in parse_item switch, and failing that try
6055 * to parse outer attributes, and then pass them in to either a let
6056 * statement or (fallback) expression statement. */
6057 // FIXME: think of a way to do this without such a large switch?
6058 t = lexer.peek_token ();
6059 switch (t->get_id ())
6060 {
6061 case LET:
6062 // let statement
6063 return parse_let_stmt (std::move (outer_attrs), restrictions);
6064 case PUB:
6065 case MOD:
7f631967 6066 case EXTERN_KW:
35e4f3b4 6067 case USE:
7f631967 6068 case FN_KW:
35e4f3b4 6069 case TYPE:
7f631967
PEP
6070 case STRUCT_KW:
6071 case ENUM_KW:
35e4f3b4 6072 case CONST:
7f631967 6073 case STATIC_KW:
22128105 6074 case AUTO:
35e4f3b4
JP
6075 case TRAIT:
6076 case IMPL:
e1394230 6077 case MACRO:
35e4f3b4
JP
6078 /* TODO: implement union keyword but not really because of
6079 * context-dependence crappy hack way to parse a union written below to
6080 * separate it from the good code. */
6081 // case UNION:
6082 case UNSAFE: // maybe - unsafe traits are a thing
6083 /* if any of these (should be all possible VisItem prefixes), parse a
6084 * VisItem can't parse item because would require reparsing outer
6085 * attributes */
d2a499a9
OA
6086 // may also be unsafe block
6087 if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
6088 {
6089 return parse_expr_stmt (std::move (outer_attrs), restrictions);
6090 }
6091 else
6092 {
6093 return parse_vis_item (std::move (outer_attrs));
6094 }
35e4f3b4 6095 break;
35e4f3b4
JP
6096 // crappy hack to do union "keyword"
6097 case IDENTIFIER:
28652f21 6098 if (t->get_str () == Values::WeakKeywords::UNION
35e4f3b4
JP
6099 && lexer.peek_token (1)->get_id () == IDENTIFIER)
6100 {
6101 return parse_vis_item (std::move (outer_attrs));
6102 // or should this go straight to parsing union?
6103 }
68a8a550 6104 else if (is_macro_rules_def (t))
35e4f3b4
JP
6105 {
6106 // macro_rules! macro item
e1394230 6107 return parse_macro_rules_def (std::move (outer_attrs));
35e4f3b4 6108 }
35e4f3b4
JP
6109 gcc_fallthrough ();
6110 // TODO: find out how to disable gcc "implicit fallthrough" warning
6111 default:
6112 // fallback: expression statement
6113 return parse_expr_stmt (std::move (outer_attrs), restrictions);
6114 break;
6115 }
6116}
6117
6118// Parses a let statement.
6119template <typename ManagedTokenSource>
6120std::unique_ptr<AST::LetStmt>
6121Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
6122 ParseRestrictions restrictions)
6123{
d991a3f1 6124 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
6125 skip_token (LET);
6126
6127 // parse pattern (required)
6128 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
6129 if (pattern == nullptr)
6130 {
6131 Error error (lexer.peek_token ()->get_locus (),
6132 "failed to parse pattern in let statement");
6133 add_error (std::move (error));
6134
6135 skip_after_semicolon ();
6136 return nullptr;
6137 }
6138
6139 // parse type declaration (optional)
6140 std::unique_ptr<AST::Type> type = nullptr;
6141 if (lexer.peek_token ()->get_id () == COLON)
6142 {
6143 // must have a type declaration
6144 lexer.skip_token ();
6145
6146 type = parse_type ();
6147 if (type == nullptr)
6148 {
6149 Error error (lexer.peek_token ()->get_locus (),
6150 "failed to parse type in let statement");
6151 add_error (std::move (error));
6152
6153 skip_after_semicolon ();
6154 return nullptr;
6155 }
6156 }
6157
6158 // parse expression to set variable to (optional)
6159 std::unique_ptr<AST::Expr> expr = nullptr;
6160 if (lexer.peek_token ()->get_id () == EQUAL)
6161 {
6162 // must have an expression
6163 lexer.skip_token ();
6164
6165 expr = parse_expr ();
6166 if (expr == nullptr)
6167 {
6168 Error error (lexer.peek_token ()->get_locus (),
6169 "failed to parse expression in let statement");
6170 add_error (std::move (error));
6171
6172 skip_after_semicolon ();
6173 return nullptr;
6174 }
6175 }
6176
010890e3
AC
6177 tl::optional<std::unique_ptr<AST::Expr>> else_expr = tl::nullopt;
6178 if (maybe_skip_token (ELSE))
6179 else_expr = parse_block_expr ();
6180
35e4f3b4 6181 if (restrictions.consume_semi)
8bc4ce7c
MJ
6182 {
6183 // `stmt` macro variables are parsed without a semicolon, but should be
6184 // parsed as a full statement when interpolated. This should be handled
6185 // by having the interpolated statement be distinguishable from normal
6186 // tokens, e.g. by NT tokens.
6187 if (restrictions.allow_close_after_expr_stmt)
6188 maybe_skip_token (SEMICOLON);
6189 else if (!skip_token (SEMICOLON))
6190 return nullptr;
6191 }
35e4f3b4
JP
6192
6193 return std::unique_ptr<AST::LetStmt> (
6194 new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
010890e3 6195 std::move (else_expr), std::move (outer_attrs), locus));
35e4f3b4
JP
6196}
6197
6198// Parses a type path.
6199template <typename ManagedTokenSource>
6200AST::TypePath
6201Parser<ManagedTokenSource>::parse_type_path ()
6202{
6203 bool has_opening_scope_resolution = false;
d991a3f1 6204 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
6205 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
6206 {
6207 has_opening_scope_resolution = true;
6208 lexer.skip_token ();
6209 }
6210
6211 // create segment vector
6212 std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
6213
6214 // parse required initial segment
6215 std::unique_ptr<AST::TypePathSegment> initial_segment
6216 = parse_type_path_segment ();
6217 if (initial_segment == nullptr)
6218 {
6219 // skip after somewhere?
6220 // don't necessarily throw error but yeah
6221 return AST::TypePath::create_error ();
6222 }
6223 segments.push_back (std::move (initial_segment));
6224
6225 // parse optional segments (as long as scope resolution operator exists)
6226 const_TokenPtr t = lexer.peek_token ();
6227 while (t->get_id () == SCOPE_RESOLUTION)
6228 {
6229 // skip scope resolution operator
6230 lexer.skip_token ();
6231
6232 // parse the actual segment - it is an error if it doesn't exist now
6233 std::unique_ptr<AST::TypePathSegment> segment
6234 = parse_type_path_segment ();
6235 if (segment == nullptr)
6236 {
6237 // skip after somewhere?
6238 Error error (t->get_locus (), "could not parse type path segment");
6239 add_error (std::move (error));
6240
6241 return AST::TypePath::create_error ();
6242 }
6243
6244 segments.push_back (std::move (segment));
6245
6246 t = lexer.peek_token ();
6247 }
6248
6249 segments.shrink_to_fit ();
6250
6251 return AST::TypePath (std::move (segments), locus,
6252 has_opening_scope_resolution);
6253}
6254
6255template <typename ManagedTokenSource>
e905c04b 6256tl::optional<AST::GenericArg>
35e4f3b4
JP
6257Parser<ManagedTokenSource>::parse_generic_arg ()
6258{
6259 auto tok = lexer.peek_token ();
6260 std::unique_ptr<AST::Expr> expr = nullptr;
6261
6262 switch (tok->get_id ())
6263 {
6264 case IDENTIFIER: {
6265 // This is a bit of a weird situation: With an identifier token, we
6266 // could either have a valid type or a macro (FIXME: anything else?). So
6267 // we need one bit of lookahead to differentiate if this is really
6268 auto next_tok = lexer.peek_token (1);
2af66ebd
AC
6269 if (next_tok->get_id () == LEFT_ANGLE
6270 || next_tok->get_id () == SCOPE_RESOLUTION
6271 || next_tok->get_id () == EXCLAM)
35e4f3b4
JP
6272 {
6273 auto type = parse_type ();
6274 if (type)
6275 return AST::GenericArg::create_type (std::move (type));
6276 else
e905c04b 6277 return tl::nullopt;
35e4f3b4 6278 }
ef792b96 6279 else if (next_tok->get_id () == COLON)
6280 {
6281 lexer.skip_token (); // skip ident
6282 lexer.skip_token (); // skip colon
6283
6284 auto tok = lexer.peek_token ();
6285 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
6286 = parse_type_param_bounds ();
6287
6288 auto type = std::unique_ptr<AST::TraitObjectType> (
6289 new AST::TraitObjectType (std::move (bounds), tok->get_locus (),
6290 false));
6291 if (type)
6292 return AST::GenericArg::create_type (std::move (type));
6293 else
e905c04b 6294 return tl::nullopt;
ef792b96 6295 }
35e4f3b4
JP
6296 lexer.skip_token ();
6297 return AST::GenericArg::create_ambiguous (tok->get_str (),
6298 tok->get_locus ());
6299 }
6300 case LEFT_CURLY:
6301 expr = parse_block_expr ();
6302 break;
6303 case MINUS:
6304 case STRING_LITERAL:
6305 case CHAR_LITERAL:
6306 case INT_LITERAL:
6307 case FLOAT_LITERAL:
6308 case TRUE_LITERAL:
6309 case FALSE_LITERAL:
6310 expr = parse_literal_expr ();
6311 break;
6312 // FIXME: Because of this, error reporting is garbage for const generic
6313 // parameter's default values
6314 default: {
6315 auto type = parse_type ();
6316 // FIXME: Find a better way to do this?
6317 if (type)
6318 return AST::GenericArg::create_type (std::move (type));
6319 else
e905c04b 6320 return tl::nullopt;
35e4f3b4
JP
6321 }
6322 }
6323
6324 if (!expr)
e905c04b 6325 return tl::nullopt;
35e4f3b4
JP
6326
6327 return AST::GenericArg::create_const (std::move (expr));
6328}
6329
6330// Parses the generic arguments in each path segment.
6331template <typename ManagedTokenSource>
6332AST::GenericArgs
6333Parser<ManagedTokenSource>::parse_path_generic_args ()
6334{
60b6cc16
AC
6335 if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
6336 lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
6337
35e4f3b4
JP
6338 if (!skip_token (LEFT_ANGLE))
6339 {
6340 // skip after somewhere?
6341 return AST::GenericArgs::create_empty ();
6342 }
6343
6344 // We need to parse all lifetimes, then parse types and const generics in
6345 // any order.
6346
6347 // try to parse lifetimes first
6348 std::vector<AST::Lifetime> lifetime_args;
6349
6350 const_TokenPtr t = lexer.peek_token ();
d991a3f1 6351 location_t locus = t->get_locus ();
35e4f3b4
JP
6352 while (!is_right_angle_tok (t->get_id ()))
6353 {
827ceac9
PEP
6354 auto lifetime = parse_lifetime (false);
6355 if (!lifetime)
35e4f3b4
JP
6356 {
6357 // not necessarily an error
6358 break;
6359 }
6360
827ceac9 6361 lifetime_args.push_back (std::move (lifetime.value ()));
35e4f3b4
JP
6362
6363 // if next token isn't comma, then it must be end of list
6364 if (lexer.peek_token ()->get_id () != COMMA)
6365 {
6366 break;
6367 }
6368 // skip comma
6369 lexer.skip_token ();
6370
6371 t = lexer.peek_token ();
6372 }
6373
6374 // try to parse types and const generics second
6375 std::vector<AST::GenericArg> generic_args;
6376
6377 // TODO: think of better control structure
6378 t = lexer.peek_token ();
6379 while (!is_right_angle_tok (t->get_id ()))
6380 {
6381 // FIXME: Is it fine to break if there is one binding? Can't there be
6382 // bindings in between types?
6383
6384 // ensure not binding being parsed as type accidently
6385 if (t->get_id () == IDENTIFIER
6386 && lexer.peek_token (1)->get_id () == EQUAL)
6387 break;
6388
6389 auto arg = parse_generic_arg ();
e905c04b 6390 if (arg)
35e4f3b4 6391 {
e905c04b 6392 generic_args.emplace_back (std::move (arg.value ()));
35e4f3b4
JP
6393 }
6394
6395 // FIXME: Do we need to break if we encounter an error?
6396
6397 // if next token isn't comma, then it must be end of list
6398 if (lexer.peek_token ()->get_id () != COMMA)
6399 break;
6400
6401 // skip comma
6402 lexer.skip_token ();
6403 t = lexer.peek_token ();
6404 }
6405
6406 // try to parse bindings third
6407 std::vector<AST::GenericArgsBinding> binding_args;
6408
6409 // TODO: think of better control structure
6410 t = lexer.peek_token ();
6411 while (!is_right_angle_tok (t->get_id ()))
6412 {
6413 AST::GenericArgsBinding binding = parse_generic_args_binding ();
6414 if (binding.is_error ())
6415 {
6416 // not necessarily an error
6417 break;
6418 }
6419
6420 binding_args.push_back (std::move (binding));
6421
6422 // if next token isn't comma, then it must be end of list
6423 if (lexer.peek_token ()->get_id () != COMMA)
6424 {
6425 break;
6426 }
6427 // skip comma
6428 lexer.skip_token ();
6429
6430 t = lexer.peek_token ();
6431 }
6432
6433 // skip any trailing commas
6434 if (lexer.peek_token ()->get_id () == COMMA)
6435 lexer.skip_token ();
6436
6437 if (!skip_generics_right_angle ())
6438 return AST::GenericArgs::create_empty ();
6439
6440 lifetime_args.shrink_to_fit ();
6441 generic_args.shrink_to_fit ();
6442 binding_args.shrink_to_fit ();
6443
6444 return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
6445 std::move (binding_args), locus);
6446}
6447
6448// Parses a binding in a generic args path segment.
6449template <typename ManagedTokenSource>
6450AST::GenericArgsBinding
6451Parser<ManagedTokenSource>::parse_generic_args_binding ()
6452{
6453 const_TokenPtr ident_tok = lexer.peek_token ();
6454 if (ident_tok->get_id () != IDENTIFIER)
6455 {
6456 // allow non error-inducing use
6457 // skip somewhere?
6458 return AST::GenericArgsBinding::create_error ();
6459 }
6460 lexer.skip_token ();
1c3a8fbb 6461 Identifier ident{ident_tok};
35e4f3b4
JP
6462
6463 if (!skip_token (EQUAL))
6464 {
6465 // skip after somewhere?
6466 return AST::GenericArgsBinding::create_error ();
6467 }
6468
6469 // parse type (required)
6470 std::unique_ptr<AST::Type> type = parse_type ();
6471 if (type == nullptr)
6472 {
6473 // skip somewhere?
6474 return AST::GenericArgsBinding::create_error ();
6475 }
6476
6477 return AST::GenericArgsBinding (std::move (ident), std::move (type),
6478 ident_tok->get_locus ());
6479}
6480
6481/* Parses a single type path segment (not including opening scope resolution,
6482 * but includes any internal ones). Includes generic args or type path
6483 * functions too. */
6484template <typename ManagedTokenSource>
6485std::unique_ptr<AST::TypePathSegment>
6486Parser<ManagedTokenSource>::parse_type_path_segment ()
6487{
d991a3f1 6488 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
6489 // parse ident segment part
6490 AST::PathIdentSegment ident_segment = parse_path_ident_segment ();
6491 if (ident_segment.is_error ())
6492 {
6493 // not necessarily an error
6494 return nullptr;
6495 }
6496
6497 /* lookahead to determine if variants exist - only consume scope resolution
6498 * then */
6499 bool has_separating_scope_resolution = false;
6500 const_TokenPtr next = lexer.peek_token (1);
6501 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
6502 && (next->get_id () == LEFT_ANGLE || next->get_id () == LEFT_PAREN))
6503 {
6504 has_separating_scope_resolution = true;
6505 lexer.skip_token ();
6506 }
6507
6508 // branch into variants on next token
6509 const_TokenPtr t = lexer.peek_token ();
6510 switch (t->get_id ())
6511 {
60b6cc16 6512 case LEFT_SHIFT:
35e4f3b4
JP
6513 case LEFT_ANGLE: {
6514 // parse generic args
6515 AST::GenericArgs generic_args = parse_path_generic_args ();
6516
6517 return std::unique_ptr<AST::TypePathSegmentGeneric> (
6518 new AST::TypePathSegmentGeneric (std::move (ident_segment),
6519 has_separating_scope_resolution,
6520 std::move (generic_args), locus));
6521 }
6522 case LEFT_PAREN: {
6523 // parse type path function
6524 AST::TypePathFunction type_path_function
6525 = parse_type_path_function (locus);
6526
6527 if (type_path_function.is_error ())
6528 {
6529 // skip after somewhere?
6530 return nullptr;
6531 }
6532
6533 return std::unique_ptr<AST::TypePathSegmentFunction> (
6534 new AST::TypePathSegmentFunction (std::move (ident_segment),
6535 has_separating_scope_resolution,
6536 std::move (type_path_function),
6537 locus));
6538 }
6539 default:
6540 // neither of them
6541 return std::unique_ptr<AST::TypePathSegment> (
6542 new AST::TypePathSegment (std::move (ident_segment),
6543 has_separating_scope_resolution, locus));
6544 }
93866b6a 6545 rust_unreachable ();
35e4f3b4
JP
6546}
6547
6548// Parses a function call representation inside a type path.
6549template <typename ManagedTokenSource>
6550AST::TypePathFunction
80c68893 6551Parser<ManagedTokenSource>::parse_type_path_function (location_t id_location)
35e4f3b4
JP
6552{
6553 if (!skip_token (LEFT_PAREN))
6554 {
6555 // skip somewhere?
6556 return AST::TypePathFunction::create_error ();
6557 }
6558
6559 // parse function inputs
6560 std::vector<std::unique_ptr<AST::Type>> inputs;
6561
6562 while (lexer.peek_token ()->get_id () != RIGHT_PAREN)
6563 {
6564 std::unique_ptr<AST::Type> type = parse_type ();
6565 if (type == nullptr)
6566 {
6567 /* this is an error as there should've been a ')' there if there
6568 * wasn't a type */
6569 Error error (
6570 lexer.peek_token ()->get_locus (),
6571 "failed to parse type in parameters of type path function");
6572 add_error (std::move (error));
6573
6574 // skip somewhere?
6575 return AST::TypePathFunction::create_error ();
6576 }
6577
6578 inputs.push_back (std::move (type));
6579
6580 // skip commas, including trailing commas
6581 if (lexer.peek_token ()->get_id () != COMMA)
6582 break;
6583
6584 lexer.skip_token ();
6585 }
6586
6587 if (!skip_token (RIGHT_PAREN))
6588 {
6589 // skip somewhere?
6590 return AST::TypePathFunction::create_error ();
6591 }
6592
6593 // parse optional return type
6594 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
6595
6596 inputs.shrink_to_fit ();
6597 return AST::TypePathFunction (std::move (inputs), id_location,
6598 std::move (return_type));
6599}
6600
6601// Parses a path inside an expression that allows generic arguments.
6602template <typename ManagedTokenSource>
6603AST::PathInExpression
6604Parser<ManagedTokenSource>::parse_path_in_expression ()
6605{
d991a3f1 6606 location_t locus = UNKNOWN_LOCATION;
35e4f3b4
JP
6607 bool has_opening_scope_resolution = false;
6608 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
6609 {
6610 has_opening_scope_resolution = true;
6611
6612 locus = lexer.peek_token ()->get_locus ();
6613
6614 lexer.skip_token ();
6615 }
6616
6617 // create segment vector
6618 std::vector<AST::PathExprSegment> segments;
6619
e5f3ad0f 6620 if (locus == UNKNOWN_LOCATION)
35e4f3b4
JP
6621 {
6622 locus = lexer.peek_token ()->get_locus ();
6623 }
6624
6625 // parse required initial segment
6626 AST::PathExprSegment initial_segment = parse_path_expr_segment ();
6627 if (initial_segment.is_error ())
6628 {
6629 // skip after somewhere?
6630 // don't necessarily throw error but yeah
6631 return AST::PathInExpression::create_error ();
6632 }
6633 segments.push_back (std::move (initial_segment));
6634
6635 // parse optional segments (as long as scope resolution operator exists)
6636 const_TokenPtr t = lexer.peek_token ();
6637 while (t->get_id () == SCOPE_RESOLUTION)
6638 {
6639 // skip scope resolution operator
6640 lexer.skip_token ();
6641
6642 // parse the actual segment - it is an error if it doesn't exist now
6643 AST::PathExprSegment segment = parse_path_expr_segment ();
6644 if (segment.is_error ())
6645 {
6646 // skip after somewhere?
6647 Error error (t->get_locus (),
6648 "could not parse path expression segment");
6649 add_error (std::move (error));
6650
6651 return AST::PathInExpression::create_error ();
6652 }
6653
6654 segments.push_back (std::move (segment));
6655
6656 t = lexer.peek_token ();
6657 }
6658
6659 segments.shrink_to_fit ();
6660
6661 return AST::PathInExpression (std::move (segments), {}, locus,
6662 has_opening_scope_resolution);
6663}
6664
6665/* Parses a single path in expression path segment (including generic
6666 * arguments). */
6667template <typename ManagedTokenSource>
6668AST::PathExprSegment
6669Parser<ManagedTokenSource>::parse_path_expr_segment ()
6670{
d991a3f1 6671 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
6672 // parse ident segment
6673 AST::PathIdentSegment ident = parse_path_ident_segment ();
6674 if (ident.is_error ())
6675 {
6676 // not necessarily an error?
6677 return AST::PathExprSegment::create_error ();
6678 }
6679
6680 // parse generic args (and turbofish), if they exist
6681 /* use lookahead to determine if they actually exist (don't want to
6682 * accidently parse over next ident segment) */
6683 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
061c5d2e
PEP
6684 && (lexer.peek_token (1)->get_id () == LEFT_ANGLE
6685 || lexer.peek_token (1)->get_id () == LEFT_SHIFT))
35e4f3b4
JP
6686 {
6687 // skip scope resolution
6688 lexer.skip_token ();
6689
061c5d2e 6690 // Let parse_path_generic_args split "<<" tokens
35e4f3b4
JP
6691 AST::GenericArgs generic_args = parse_path_generic_args ();
6692
6693 return AST::PathExprSegment (std::move (ident), locus,
6694 std::move (generic_args));
6695 }
6696
6697 // return a generic parameter-less expr segment if not found
6698 return AST::PathExprSegment (std::move (ident), locus);
6699}
6700
6701/* Parses a fully qualified path in expression (i.e. a pattern). FIXME does
6702 * not parse outer attrs. */
6703template <typename ManagedTokenSource>
6704AST::QualifiedPathInExpression
6705Parser<ManagedTokenSource>::parse_qualified_path_in_expression (
80c68893 6706 location_t pratt_parsed_loc)
35e4f3b4
JP
6707{
6708 /* Note: the Rust grammar is defined in such a way that it is impossible to
6709 * determine whether a prospective qualified path is a
6710 * QualifiedPathInExpression or QualifiedPathInType in all cases by the
6711 * rules themselves (the only possible difference is a TypePathSegment with
6712 * function, and lookahead to find this is too difficult). However, as this
6713 * is a pattern and QualifiedPathInType is a type, I believe it that their
6714 * construction will not be confused (due to rules regarding patterns vs
6715 * types).
6716 * As such, this function will not attempt to minimise errors created by
6717 * their confusion. */
6718
6719 // parse the qualified path type (required)
6720 AST::QualifiedPathType qual_path_type
6721 = parse_qualified_path_type (pratt_parsed_loc);
6722 if (qual_path_type.is_error ())
6723 {
6724 // TODO: should this create a parse error?
6725 return AST::QualifiedPathInExpression::create_error ();
6726 }
d991a3f1 6727 location_t locus = qual_path_type.get_locus ();
35e4f3b4
JP
6728
6729 // parse path segments
6730 std::vector<AST::PathExprSegment> segments;
6731
6732 // parse initial required segment
6733 if (!expect_token (SCOPE_RESOLUTION))
6734 {
6735 // skip after somewhere?
6736
6737 return AST::QualifiedPathInExpression::create_error ();
6738 }
6739 AST::PathExprSegment initial_segment = parse_path_expr_segment ();
6740 if (initial_segment.is_error ())
6741 {
6742 // skip after somewhere?
6743 Error error (lexer.peek_token ()->get_locus (),
6744 "required initial path expression segment in "
6745 "qualified path in expression could not be parsed");
6746 add_error (std::move (error));
6747
6748 return AST::QualifiedPathInExpression::create_error ();
6749 }
6750 segments.push_back (std::move (initial_segment));
6751
6752 // parse optional segments (as long as scope resolution operator exists)
6753 const_TokenPtr t = lexer.peek_token ();
6754 while (t->get_id () == SCOPE_RESOLUTION)
6755 {
6756 // skip scope resolution operator
6757 lexer.skip_token ();
6758
6759 // parse the actual segment - it is an error if it doesn't exist now
6760 AST::PathExprSegment segment = parse_path_expr_segment ();
6761 if (segment.is_error ())
6762 {
6763 // skip after somewhere?
6764 Error error (t->get_locus (),
6765 "could not parse path expression segment in qualified "
6766 "path in expression");
6767 add_error (std::move (error));
6768
6769 return AST::QualifiedPathInExpression::create_error ();
6770 }
6771
6772 segments.push_back (std::move (segment));
6773
6774 t = lexer.peek_token ();
6775 }
6776
6777 segments.shrink_to_fit ();
6778
6779 // FIXME: outer attr parsing
6780 return AST::QualifiedPathInExpression (std::move (qual_path_type),
6781 std::move (segments), {}, locus);
6782}
6783
6784// Parses the type syntactical construction at the start of a qualified path.
6785template <typename ManagedTokenSource>
6786AST::QualifiedPathType
6787Parser<ManagedTokenSource>::parse_qualified_path_type (
80c68893 6788 location_t pratt_parsed_loc)
35e4f3b4 6789{
d991a3f1 6790 location_t locus = pratt_parsed_loc;
35e4f3b4
JP
6791 /* TODO: should this actually be error? is there anywhere where this could
6792 * be valid? */
e5f3ad0f 6793 if (locus == UNKNOWN_LOCATION)
35e4f3b4
JP
6794 {
6795 locus = lexer.peek_token ()->get_locus ();
2a094010
AC
6796
6797 if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
6798 lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
6799
6800 // skip after somewhere?
35e4f3b4 6801 if (!skip_token (LEFT_ANGLE))
2a094010 6802 return AST::QualifiedPathType::create_error ();
35e4f3b4
JP
6803 }
6804
6805 // parse type (required)
6806 std::unique_ptr<AST::Type> type = parse_type ();
6807 if (type == nullptr)
6808 {
6809 Error error (lexer.peek_token ()->get_locus (),
6810 "could not parse type in qualified path type");
6811 add_error (std::move (error));
6812
6813 // skip somewhere?
6814 return AST::QualifiedPathType::create_error ();
6815 }
6816
6817 // parse optional as clause
6818 AST::TypePath as_type_path = AST::TypePath::create_error ();
6819 if (lexer.peek_token ()->get_id () == AS)
6820 {
6821 lexer.skip_token ();
6822
6823 // parse type path, which is required now
6824 as_type_path = parse_type_path ();
6825 if (as_type_path.is_error ())
6826 {
6827 Error error (
6828 lexer.peek_token ()->get_locus (),
6829 "could not parse type path in as clause in qualified path type");
6830 add_error (std::move (error));
6831
6832 // skip somewhere?
6833 return AST::QualifiedPathType::create_error ();
6834 }
6835 }
6836
6837 /* NOTE: should actually be a right-angle token, so
6838 * skip_generics_right_angle shouldn't be required */
6839 if (!skip_token (RIGHT_ANGLE))
6840 {
6841 // skip after somewhere?
6842 return AST::QualifiedPathType::create_error ();
6843 }
6844
6845 return AST::QualifiedPathType (std::move (type), locus,
6846 std::move (as_type_path));
6847}
6848
6849// Parses a fully qualified path in type (i.e. a type).
6850template <typename ManagedTokenSource>
6851AST::QualifiedPathInType
6852Parser<ManagedTokenSource>::parse_qualified_path_in_type ()
6853{
d991a3f1 6854 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4
JP
6855 // parse the qualified path type (required)
6856 AST::QualifiedPathType qual_path_type = parse_qualified_path_type ();
6857 if (qual_path_type.is_error ())
6858 {
6859 // TODO: should this create a parse error?
6860 return AST::QualifiedPathInType::create_error ();
6861 }
6862
6863 // parse initial required segment
6864 if (!expect_token (SCOPE_RESOLUTION))
6865 {
6866 // skip after somewhere?
6867
6868 return AST::QualifiedPathInType::create_error ();
6869 }
6870 std::unique_ptr<AST::TypePathSegment> initial_segment
6871 = parse_type_path_segment ();
6872 if (initial_segment == nullptr)
6873 {
6874 // skip after somewhere?
6875 Error error (lexer.peek_token ()->get_locus (),
6876 "required initial type path segment in qualified path in "
6877 "type could not be parsed");
6878 add_error (std::move (error));
6879
6880 return AST::QualifiedPathInType::create_error ();
6881 }
6882
6883 // parse optional segments (as long as scope resolution operator exists)
6884 std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
6885 const_TokenPtr t = lexer.peek_token ();
6886 while (t->get_id () == SCOPE_RESOLUTION)
6887 {
6888 // skip scope resolution operator
6889 lexer.skip_token ();
6890
6891 // parse the actual segment - it is an error if it doesn't exist now
6892 std::unique_ptr<AST::TypePathSegment> segment
6893 = parse_type_path_segment ();
6894 if (segment == nullptr)
6895 {
6896 // skip after somewhere?
6897 Error error (
6898 t->get_locus (),
6899 "could not parse type path segment in qualified path in type");
6900 add_error (std::move (error));
6901
6902 return AST::QualifiedPathInType::create_error ();
6903 }
6904
6905 segments.push_back (std::move (segment));
6906
6907 t = lexer.peek_token ();
6908 }
6909
6910 segments.shrink_to_fit ();
6911
6912 return AST::QualifiedPathInType (std::move (qual_path_type),
6913 std::move (initial_segment),
6914 std::move (segments), locus);
6915}
6916
6917// Parses a self param. Also handles self param not existing.
6918template <typename ManagedTokenSource>
3e450ae1 6919tl::expected<std::unique_ptr<AST::Param>, ParseSelfError>
35e4f3b4
JP
6920Parser<ManagedTokenSource>::parse_self_param ()
6921{
6922 bool has_reference = false;
50f30592 6923 AST::Lifetime lifetime = AST::Lifetime::elided ();
35e4f3b4 6924
d991a3f1 6925 location_t locus = lexer.peek_token ()->get_locus ();
35e4f3b4 6926
513b0154
PEP
6927 // TODO: Feels off, find a better way to clearly express this
6928 std::vector<std::vector<TokenId>> ptrs
6929 = {{ASTERISK, SELF} /* *self */,
6930 {ASTERISK, CONST, SELF} /* *const self */,
6931 {ASTERISK, MUT, SELF} /* *mut self */};
6932
6933 for (auto &s : ptrs)
6934 {
6935 size_t i = 0;
ca16a3ee 6936 for (i = 0; i < s.size (); i++)
513b0154
PEP
6937 if (lexer.peek_token (i)->get_id () != s[i])
6938 break;
6939 if (i == s.size ())
3e450ae1
PEP
6940 {
6941 rust_error_at (lexer.peek_token ()->get_locus (),
6942 "cannot pass %<self%> by raw pointer");
6943 return tl::make_unexpected (ParseSelfError::SELF_PTR);
6944 }
513b0154
PEP
6945 }
6946
6947 // Trying to find those patterns:
6948 //
6949 // &'lifetime mut self
6950 // &'lifetime self
6951 // & mut self
6952 // & self
6953 // mut self
6954 // self
6955 //
6956 // If not found, it is probably a function, exit and let function parsing
6957 // handle it.
6958 bool is_self = false;
6959 for (size_t i = 0; i < 5; i++)
6960 if (lexer.peek_token (i)->get_id () == SELF)
6961 is_self = true;
6962
6963 if (!is_self)
3e450ae1 6964 return tl::make_unexpected (ParseSelfError::NOT_SELF);
513b0154 6965
35e4f3b4
JP
6966 // test if self is a reference parameter
6967 if (lexer.peek_token ()->get_id () == AMP)
6968 {
6969 has_reference = true;
6970 lexer.skip_token ();
6971
6972 // now test whether it has a lifetime
6973 if (lexer.peek_token ()->get_id () == LIFETIME)
6974 {
35e4f3b4 6975 // something went wrong somehow
827ceac9
PEP
6976 if (auto parsed_lifetime = parse_lifetime (true))
6977 {
6978 lifetime = parsed_lifetime.value ();
6979 }
6980 else
35e4f3b4
JP
6981 {
6982 Error error (lexer.peek_token ()->get_locus (),
6983 "failed to parse lifetime in self param");
6984 add_error (std::move (error));
6985
6986 // skip after somewhere?
3e450ae1 6987 return tl::make_unexpected (ParseSelfError::PARSING);
35e4f3b4
JP
6988 }
6989 }
6990 }
6991
6992 // test for mut
6993 bool has_mut = false;
6994 if (lexer.peek_token ()->get_id () == MUT)
6995 {
6996 has_mut = true;
6997 lexer.skip_token ();
6998 }
6999
7000 // skip self token
7001 const_TokenPtr self_tok = lexer.peek_token ();
7002 if (self_tok->get_id () != SELF)
7003 {
7004 // skip after somewhere?
3e450ae1 7005 return tl::make_unexpected (ParseSelfError::NOT_SELF);
35e4f3b4
JP
7006 }
7007 lexer.skip_token ();
7008
7009 // parse optional type
7010 std::unique_ptr<AST::Type> type = nullptr;
7011 if (lexer.peek_token ()->get_id () == COLON)
7012 {
7013 lexer.skip_token ();
7014
7015 // type is now required
7016 type = parse_type ();
7017 if (type == nullptr)
7018 {
7019 Error error (lexer.peek_token ()->get_locus (),
7020 "could not parse type in self param");
7021 add_error (std::move (error));
7022
7023 // skip after somewhere?
3e450ae1 7024 return tl::make_unexpected (ParseSelfError::PARSING);
35e4f3b4
JP
7025 }
7026 }
7027
7028 // ensure that cannot have both type and reference
7029 if (type != nullptr && has_reference)
7030 {
7031 Error error (
7032 lexer.peek_token ()->get_locus (),
7033 "cannot have both a reference and a type specified in a self param");
7034 add_error (std::move (error));
7035
7036 // skip after somewhere?
3e450ae1 7037 return tl::make_unexpected (ParseSelfError::PARSING);
35e4f3b4
JP
7038 }
7039
7040 if (has_reference)
7041 {
c8721ccd
OA
7042 return std::make_unique<AST::SelfParam> (std::move (lifetime), has_mut,
7043 locus);
35e4f3b4
JP
7044 }
7045 else
7046 {
7047 // note that type may be nullptr here and that's fine
c8721ccd
OA
7048 return std::make_unique<AST::SelfParam> (std::move (type), has_mut,
7049 locus);
32c8fb0e 7050 }
32c8fb0e
JP
7051}
7052
8bc4ce7c 7053/* Parses an expression or macro statement. */
32c8fb0e 7054template <typename ManagedTokenSource>
8bc4ce7c 7055std::unique_ptr<AST::Stmt>
32c8fb0e
JP
7056Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
7057 ParseRestrictions restrictions)
7058{
d991a3f1 7059 location_t locus = lexer.peek_token ()->get_locus ();
32c8fb0e 7060
8bc4ce7c
MJ
7061 std::unique_ptr<AST::Expr> expr;
7062
7063 switch (lexer.peek_token ()->get_id ())
7064 {
7065 case IDENTIFIER:
7066 case CRATE:
7067 case SUPER:
7068 case SELF:
7069 case SELF_ALIAS:
7070 case DOLLAR_SIGN:
7071 case SCOPE_RESOLUTION: {
7072 AST::PathInExpression path = parse_path_in_expression ();
7073 std::unique_ptr<AST::Expr> null_denotation;
7074
7075 if (lexer.peek_token ()->get_id () == EXCLAM)
7076 {
7077 // Bind a reference to avoid -Wredundant-move on post-P1825R0
7078 // compilers. Change to non-reference type and remove the moves
7079 // below once C++20 is required to build gcc.
7080 std::unique_ptr<AST::MacroInvocation> &&invoc
7081 = parse_macro_invocation_partial (std::move (path),
7082 std::move (outer_attrs));
7083
7084 if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
7085 {
7086 invoc->add_semicolon ();
7087 // Macro invocation with semicolon.
7088 return std::move (invoc);
7089 }
7090
7091 TokenId after_macro = lexer.peek_token ()->get_id ();
7092
7093 if (restrictions.allow_close_after_expr_stmt
7094 && (after_macro == RIGHT_PAREN || after_macro == RIGHT_CURLY
7095 || after_macro == RIGHT_SQUARE))
7096 return std::move (invoc);
7097
7098 if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
7099 == AST::CURLY
7100 && after_macro != DOT && after_macro != QUESTION_MARK)
7101 {
7102 rust_debug ("braced macro statement");
7103 return std::move (invoc);
7104 }
7105
7106 null_denotation = std::move (invoc);
7107 }
7108 else
7109 {
7110 null_denotation
7111 = null_denotation_path (std::move (path), {}, restrictions);
7112 }
7113
7114 expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
7115 std::move (outer_attrs), restrictions);
7116 break;
7117 }
7118 default:
7119 restrictions.expr_can_be_stmt = true;
7120 expr = parse_expr (std::move (outer_attrs), restrictions);
7121 break;
7122 }
32c8fb0e 7123
32c8fb0e
JP
7124 if (expr == nullptr)
7125 {
7126 // expr is required, error
7127 Error error (lexer.peek_token ()->get_locus (),
48408712 7128 "failed to parse expr in expr statement");
32c8fb0e
JP
7129 add_error (std::move (error));
7130
7131 skip_after_semicolon ();
7132 return nullptr;
7133 }
7134
48408712 7135 bool has_semi = false;
32c8fb0e 7136
48408712 7137 if (restrictions.consume_semi)
32c8fb0e 7138 {
8bc4ce7c
MJ
7139 if (maybe_skip_token (SEMICOLON))
7140 {
7141 has_semi = true;
7142 }
48408712 7143 else if (expr->is_expr_without_block ())
8bc4ce7c
MJ
7144 {
7145 if (restrictions.allow_close_after_expr_stmt)
7146 {
7147 TokenId id = lexer.peek_token ()->get_id ();
7148 if (id != RIGHT_PAREN && id != RIGHT_CURLY && id != RIGHT_SQUARE)
7149 {
7150 expect_token (SEMICOLON);
7151 return nullptr;
7152 }
7153 }
7154 else
7155 {
7156 expect_token (SEMICOLON);
7157 return nullptr;
7158 }
7159 }
32c8fb0e 7160 }
48408712
MJ
7161
7162 return std::unique_ptr<AST::ExprStmt> (
7163 new AST::ExprStmt (std::move (expr), locus, has_semi));
32c8fb0e
JP
7164}
7165
7166// Parses a block expression, including the curly braces at start and end.
7167template <typename ManagedTokenSource>
7168std::unique_ptr<AST::BlockExpr>
ff04ba26
PEP
7169Parser<ManagedTokenSource>::parse_block_expr (
7170 AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label,
7171 location_t pratt_parsed_loc)
32c8fb0e 7172{
d991a3f1 7173 location_t locus = pratt_parsed_loc;
e5f3ad0f 7174 if (locus == UNKNOWN_LOCATION)
32c8fb0e
JP
7175 {
7176 locus = lexer.peek_token ()->get_locus ();
7177 if (!skip_token (LEFT_CURLY))
7178 {
7179 skip_after_end_block ();
7180 return nullptr;
7181 }
7182 }
7183
7184 AST::AttrVec inner_attrs = parse_inner_attributes ();
7185
7186 // parse statements and expression
7187 std::vector<std::unique_ptr<AST::Stmt>> stmts;
7188 std::unique_ptr<AST::Expr> expr = nullptr;
7189
7190 const_TokenPtr t = lexer.peek_token ();
7191 while (t->get_id () != RIGHT_CURLY)
7192 {
48408712 7193 ExprOrStmt expr_or_stmt = parse_stmt_or_expr ();
32c8fb0e
JP
7194 if (expr_or_stmt.is_error ())
7195 {
48408712
MJ
7196 Error error (
7197 t->get_locus (),
7198 "failed to parse statement or expression in block expression");
32c8fb0e
JP
7199 add_error (std::move (error));
7200
7201 return nullptr;
7202 }
7203
7204 t = lexer.peek_token ();
7205
7206 if (expr_or_stmt.stmt != nullptr)
7207 {
7208 stmts.push_back (std::move (expr_or_stmt.stmt));
7209 }
7210 else
7211 {
7212 // assign to expression and end parsing inside
7213 expr = std::move (expr_or_stmt.expr);
7214 break;
7215 }
7216 }
7217
80c68893 7218 location_t end_locus = t->get_locus ();
32c8fb0e
JP
7219
7220 if (!skip_token (RIGHT_CURLY))
7221 {
7222 Error error (t->get_locus (),
7223 "error may be from having an expression (as opposed to "
7224 "statement) in the body of the function but not last");
7225 add_error (std::move (error));
7226
7227 skip_after_end_block ();
7228 return nullptr;
7229 }
7230
7231 // grammar allows for empty block expressions
7232
7233 stmts.shrink_to_fit ();
7234
7235 return std::unique_ptr<AST::BlockExpr> (
7236 new AST::BlockExpr (std::move (stmts), std::move (expr),
3b1d27f7
JD
7237 std::move (inner_attrs), std::move (outer_attrs),
7238 std::move (label), locus, end_locus));
32c8fb0e
JP
7239}
7240
7241/* Parses a "grouped" expression (expression in parentheses), used to control
7242 * precedence. */
7243template <typename ManagedTokenSource>
7244std::unique_ptr<AST::GroupedExpr>
7245Parser<ManagedTokenSource>::parse_grouped_expr (AST::AttrVec outer_attrs)
7246{
d991a3f1 7247 location_t locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
7248 skip_token (LEFT_PAREN);
7249
7250 AST::AttrVec inner_attrs = parse_inner_attributes ();
7251
7252 // parse required expr inside parentheses
7253 std::unique_ptr<AST::Expr> expr_in_parens = parse_expr ();
7254 if (expr_in_parens == nullptr)
7255 {
7256 // skip after somewhere?
7257 // error?
7258 return nullptr;
7259 }
7260
7261 if (!skip_token (RIGHT_PAREN))
7262 {
7263 // skip after somewhere?
7264 return nullptr;
7265 }
7266
7267 return std::unique_ptr<AST::GroupedExpr> (
7268 new AST::GroupedExpr (std::move (expr_in_parens), std::move (inner_attrs),
7269 std::move (outer_attrs), locus));
7270}
7271
7272// Parses a closure expression (closure definition).
7273template <typename ManagedTokenSource>
7274std::unique_ptr<AST::ClosureExpr>
7275Parser<ManagedTokenSource>::parse_closure_expr (AST::AttrVec outer_attrs)
7276{
d991a3f1 7277 location_t locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
7278 // detect optional "move"
7279 bool has_move = false;
7280 if (lexer.peek_token ()->get_id () == MOVE)
7281 {
7282 lexer.skip_token ();
7283 has_move = true;
7284 }
7285
7286 // handle parameter list
7287 std::vector<AST::ClosureParam> params;
7288
7289 const_TokenPtr t = lexer.peek_token ();
7290 switch (t->get_id ())
7291 {
7292 case OR:
7293 // skip token, no parameters
7294 lexer.skip_token ();
7295 break;
7296 case PIPE:
7297 // actually may have parameters
7298 lexer.skip_token ();
7f5144d1 7299 t = lexer.peek_token ();
32c8fb0e
JP
7300
7301 while (t->get_id () != PIPE)
7302 {
7303 AST::ClosureParam param = parse_closure_param ();
7304 if (param.is_error ())
7305 {
7306 // TODO is this really an error?
7307 Error error (t->get_locus (), "could not parse closure param");
7308 add_error (std::move (error));
7309
7310 break;
7311 }
7312 params.push_back (std::move (param));
7313
7314 if (lexer.peek_token ()->get_id () != COMMA)
7315 {
7f5144d1 7316 lexer.skip_token ();
32c8fb0e
JP
7317 // not an error but means param list is done
7318 break;
7319 }
7320 // skip comma
7321 lexer.skip_token ();
7322
7323 t = lexer.peek_token ();
7324 }
7325 params.shrink_to_fit ();
7326 break;
7327 default:
7328 add_error (Error (t->get_locus (),
7329 "unexpected token %qs in closure expression - expected "
7330 "%<|%> or %<||%>",
7331 t->get_token_description ()));
7332
7333 // skip somewhere?
7334 return nullptr;
7335 }
7336
7337 // again branch based on next token
7338 t = lexer.peek_token ();
7339 if (t->get_id () == RETURN_TYPE)
7340 {
7341 // must be return type closure with block expr
7342
7343 // skip "return type" token
7344 lexer.skip_token ();
7345
7346 // parse actual type, which is required
7347 std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
7348 if (type == nullptr)
7349 {
7350 // error
7351 Error error (t->get_locus (), "failed to parse type for closure");
7352 add_error (std::move (error));
7353
7354 // skip somewhere?
7355 return nullptr;
7356 }
7357
7358 // parse block expr, which is required
7359 std::unique_ptr<AST::BlockExpr> block = parse_block_expr ();
7360 if (block == nullptr)
7361 {
7362 // error
7363 Error error (lexer.peek_token ()->get_locus (),
7364 "failed to parse block expr in closure");
7365 add_error (std::move (error));
7366
7367 // skip somewhere?
7368 return nullptr;
7369 }
7370
7371 return std::unique_ptr<AST::ClosureExprInnerTyped> (
7372 new AST::ClosureExprInnerTyped (std::move (type), std::move (block),
7373 std::move (params), locus, has_move,
7374 std::move (outer_attrs)));
7375 }
7376 else
7377 {
7378 // must be expr-only closure
7379
7380 // parse expr, which is required
7381 std::unique_ptr<AST::Expr> expr = parse_expr ();
7382 if (expr == nullptr)
7383 {
7384 Error error (t->get_locus (),
7385 "failed to parse expression in closure");
7386 add_error (std::move (error));
7387
7388 // skip somewhere?
7389 return nullptr;
7390 }
7391
7392 return std::unique_ptr<AST::ClosureExprInner> (
7393 new AST::ClosureExprInner (std::move (expr), std::move (params), locus,
7394 has_move, std::move (outer_attrs)));
7395 }
7396}
7397
7398// Parses a literal token (to literal expression).
7399template <typename ManagedTokenSource>
7400std::unique_ptr<AST::LiteralExpr>
7401Parser<ManagedTokenSource>::parse_literal_expr (AST::AttrVec outer_attrs)
7402{
7403 // TODO: change if literal representation in lexer changes
7404
7405 std::string literal_value;
7406 AST::Literal::LitType type = AST::Literal::STRING;
7407
7408 // branch based on token
7409 const_TokenPtr t = lexer.peek_token ();
7410 switch (t->get_id ())
7411 {
7412 case CHAR_LITERAL:
7413 type = AST::Literal::CHAR;
7414 literal_value = t->get_str ();
7415 lexer.skip_token ();
7416 break;
7417 case STRING_LITERAL:
7418 type = AST::Literal::STRING;
7419 literal_value = t->get_str ();
7420 lexer.skip_token ();
7421 break;
7422 case BYTE_CHAR_LITERAL:
7423 type = AST::Literal::BYTE;
7424 literal_value = t->get_str ();
7425 lexer.skip_token ();
7426 break;
7427 case BYTE_STRING_LITERAL:
7428 type = AST::Literal::BYTE_STRING;
7429 literal_value = t->get_str ();
7430 lexer.skip_token ();
7431 break;
908a4f88 7432 case RAW_STRING_LITERAL:
7433 type = AST::Literal::RAW_STRING;
7434 literal_value = t->get_str ();
7435 lexer.skip_token ();
7436 break;
32c8fb0e
JP
7437 case INT_LITERAL:
7438 type = AST::Literal::INT;
7439 literal_value = t->get_str ();
7440 lexer.skip_token ();
7441 break;
7442 case FLOAT_LITERAL:
7443 type = AST::Literal::FLOAT;
7444 literal_value = t->get_str ();
7445 lexer.skip_token ();
7446 break;
7447 // case BOOL_LITERAL
7448 // use true and false keywords rather than "bool literal" Rust terminology
7449 case TRUE_LITERAL:
7450 type = AST::Literal::BOOL;
f1c7ce7e 7451 literal_value = Values::Keywords::TRUE_LITERAL;
32c8fb0e
JP
7452 lexer.skip_token ();
7453 break;
7454 case FALSE_LITERAL:
7455 type = AST::Literal::BOOL;
f1c7ce7e 7456 literal_value = Values::Keywords::FALSE_LITERAL;
32c8fb0e
JP
7457 lexer.skip_token ();
7458 break;
7459 default:
7460 // error - cannot be a literal expr
7461 add_error (Error (t->get_locus (),
7462 "unexpected token %qs when parsing literal expression",
7463 t->get_token_description ()));
7464
7465 // skip?
7466 return nullptr;
7467 }
7468
7469 // create literal based on stuff in switch
7470 return std::unique_ptr<AST::LiteralExpr> (
7471 new AST::LiteralExpr (std::move (literal_value), std::move (type),
7472 t->get_type_hint (), std::move (outer_attrs),
7473 t->get_locus ()));
7474}
7475
813a1e61
PEP
7476template <typename ManagedTokenSource>
7477std::unique_ptr<AST::BoxExpr>
7478Parser<ManagedTokenSource>::parse_box_expr (AST::AttrVec outer_attrs,
7479 location_t pratt_parsed_loc)
7480{
7481 location_t locus = pratt_parsed_loc;
7482 if (locus == UNKNOWN_LOCATION)
7483 {
7484 locus = lexer.peek_token ()->get_locus ();
7485 skip_token (BOX);
7486 }
7487
7488 ParseRestrictions restrictions;
7489 restrictions.expr_can_be_null = false;
7490
7491 std::unique_ptr<AST::Expr> expr = parse_expr (AST::AttrVec (), restrictions);
7492
7493 return std::unique_ptr<AST::BoxExpr> (
7494 new AST::BoxExpr (std::move (expr), std::move (outer_attrs), locus));
7495}
7496
32c8fb0e
JP
7497// Parses a return expression (including any expression to return).
7498template <typename ManagedTokenSource>
7499std::unique_ptr<AST::ReturnExpr>
7500Parser<ManagedTokenSource>::parse_return_expr (AST::AttrVec outer_attrs,
80c68893 7501 location_t pratt_parsed_loc)
32c8fb0e 7502{
d991a3f1 7503 location_t locus = pratt_parsed_loc;
e5f3ad0f 7504 if (locus == UNKNOWN_LOCATION)
32c8fb0e
JP
7505 {
7506 locus = lexer.peek_token ()->get_locus ();
7f631967 7507 skip_token (RETURN_KW);
32c8fb0e
JP
7508 }
7509
7510 // parse expression to return, if it exists
7511 ParseRestrictions restrictions;
7512 restrictions.expr_can_be_null = true;
7513 std::unique_ptr<AST::Expr> returned_expr
7514 = parse_expr (AST::AttrVec (), restrictions);
7515
7516 return std::unique_ptr<AST::ReturnExpr> (
7517 new AST::ReturnExpr (std::move (returned_expr), std::move (outer_attrs),
7518 locus));
7519}
7520
7521/* Parses a break expression (including any label to break to AND any return
7522 * expression). */
7523template <typename ManagedTokenSource>
7524std::unique_ptr<AST::BreakExpr>
7525Parser<ManagedTokenSource>::parse_break_expr (AST::AttrVec outer_attrs,
80c68893 7526 location_t pratt_parsed_loc)
32c8fb0e 7527{
d991a3f1 7528 location_t locus = pratt_parsed_loc;
e5f3ad0f 7529 if (locus == UNKNOWN_LOCATION)
32c8fb0e
JP
7530 {
7531 locus = lexer.peek_token ()->get_locus ();
7532 skip_token (BREAK);
7533 }
7534
827ceac9
PEP
7535 auto parsed_label = parse_lifetime (false);
7536 auto label = (parsed_label)
7537 ? tl::optional<AST::Lifetime> (parsed_label.value ())
7538 : tl::nullopt;
32c8fb0e
JP
7539
7540 // parse break return expression if it exists
7541 ParseRestrictions restrictions;
7542 restrictions.expr_can_be_null = true;
7543 std::unique_ptr<AST::Expr> return_expr
7544 = parse_expr (AST::AttrVec (), restrictions);
7545
7546 return std::unique_ptr<AST::BreakExpr> (
7547 new AST::BreakExpr (std::move (label), std::move (return_expr),
7548 std::move (outer_attrs), locus));
7549}
7550
7551// Parses a continue expression (including any label to continue from).
7552template <typename ManagedTokenSource>
7553std::unique_ptr<AST::ContinueExpr>
7554Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs,
80c68893 7555 location_t pratt_parsed_loc)
32c8fb0e 7556{
d991a3f1 7557 location_t locus = pratt_parsed_loc;
e5f3ad0f 7558 if (locus == UNKNOWN_LOCATION)
32c8fb0e
JP
7559 {
7560 locus = lexer.peek_token ()->get_locus ();
7561 skip_token (CONTINUE);
7562 }
7563
827ceac9
PEP
7564 auto parsed_label = parse_lifetime (false);
7565 auto label = (parsed_label)
7566 ? tl::optional<AST::Lifetime> (parsed_label.value ())
7567 : tl::nullopt;
32c8fb0e
JP
7568
7569 return std::unique_ptr<AST::ContinueExpr> (
7570 new AST::ContinueExpr (std::move (label), std::move (outer_attrs), locus));
7571}
7572
7573// Parses a loop label used in loop expressions.
7574template <typename ManagedTokenSource>
37908277 7575tl::expected<AST::LoopLabel, ParseLoopLabelError>
48408712 7576Parser<ManagedTokenSource>::parse_loop_label (const_TokenPtr tok)
32c8fb0e
JP
7577{
7578 // parse lifetime - if doesn't exist, assume no label
48408712 7579 if (tok->get_id () != LIFETIME)
32c8fb0e
JP
7580 {
7581 // not necessarily an error
37908277
PEP
7582 return tl::unexpected<ParseLoopLabelError> (
7583 ParseLoopLabelError::NOT_LOOP_LABEL);
32c8fb0e
JP
7584 }
7585 /* FIXME: check for named lifetime requirement here? or check in semantic
7586 * analysis phase? */
48408712 7587 AST::Lifetime label = lifetime_from_token (tok);
32c8fb0e
JP
7588
7589 if (!skip_token (COLON))
7590 {
7591 // skip somewhere?
37908277
PEP
7592 return tl::unexpected<ParseLoopLabelError> (
7593 ParseLoopLabelError::MISSING_COLON);
32c8fb0e
JP
7594 }
7595
37908277 7596 return tl::expected<AST::LoopLabel, ParseLoopLabelError> (
ff04ba26 7597 AST::LoopLabel (std::move (label), tok->get_locus ()));
32c8fb0e
JP
7598}
7599
7600/* Parses an if expression of any kind, including with else, else if, else if
7601 * let, and neither. Note that any outer attributes will be ignored because if
7602 * expressions don't support them. */
7603template <typename ManagedTokenSource>
7604std::unique_ptr<AST::IfExpr>
7605Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs,
80c68893 7606 location_t pratt_parsed_loc)
32c8fb0e
JP
7607{
7608 // TODO: make having outer attributes an error?
d991a3f1 7609 location_t locus = pratt_parsed_loc;
e5f3ad0f 7610 if (locus == UNKNOWN_LOCATION)
32c8fb0e
JP
7611 {
7612 locus = lexer.peek_token ()->get_locus ();
7613 if (!skip_token (IF))
7614 {
7615 skip_after_end_block ();
7616 return nullptr;
7617 }
7618 }
7619
7620 // detect accidental if let
7621 if (lexer.peek_token ()->get_id () == LET)
7622 {
7623 Error error (lexer.peek_token ()->get_locus (),
7624 "if let expression probably exists, but is being parsed "
7625 "as an if expression. This may be a parser error");
7626 add_error (std::move (error));
7627
7628 // skip somewhere?
7629 return nullptr;
7630 }
7631
7632 /* parse required condition expr - HACK to prevent struct expr from being
7633 * parsed */
7634 ParseRestrictions no_struct_expr;
7635 no_struct_expr.can_be_struct_expr = false;
7636 std::unique_ptr<AST::Expr> condition = parse_expr ({}, no_struct_expr);
7637 if (condition == nullptr)
7638 {
7639 Error error (lexer.peek_token ()->get_locus (),
7640 "failed to parse condition expression in if expression");
7641 add_error (std::move (error));
7642
7643 // skip somewhere?
7644 return nullptr;
7645 }
7646
7647 // parse required block expr
7648 std::unique_ptr<AST::BlockExpr> if_body = parse_block_expr ();
7649 if (if_body == nullptr)
7650 {
7651 Error error (lexer.peek_token ()->get_locus (),
7652 "failed to parse if body block expression in if expression");
7653 add_error (std::move (error));
7654
7655 // skip somewhere?
7656 return nullptr;
7657 }
7658
7659 // branch to parse end or else (and then else, else if, or else if let)
7660 if (lexer.peek_token ()->get_id () != ELSE)
7661 {
7662 // single selection - end of if expression
7663 return std::unique_ptr<AST::IfExpr> (
7664 new AST::IfExpr (std::move (condition), std::move (if_body),
7665 std::move (outer_attrs), locus));
7666 }
7667 else
7668 {
7669 // double or multiple selection - branch on end, else if, or else if let
7670
7671 // skip "else"
7672 lexer.skip_token ();
7673
7674 // branch on whether next token is '{' or 'if'
7675 const_TokenPtr t = lexer.peek_token ();
7676 switch (t->get_id ())
7677 {
7678 case LEFT_CURLY: {
7679 // double selection - else
7680 // parse else block expr (required)
7681 std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr ();
7682 if (else_body == nullptr)
7683 {
7684 Error error (lexer.peek_token ()->get_locus (),
7685 "failed to parse else body block expression in "
7686 "if expression");
7687 add_error (std::move (error));
7688
7689 // skip somewhere?
7690 return nullptr;
7691 }
7692
7693 return std::unique_ptr<AST::IfExprConseqElse> (
7694 new AST::IfExprConseqElse (std::move (condition),
7695 std::move (if_body),
7696 std::move (else_body),
7697 std::move (outer_attrs), locus));
7698 }
7699 case IF: {
7700 // multiple selection - else if or else if let
7701 // branch on whether next token is 'let' or not
7702 if (lexer.peek_token (1)->get_id () == LET)
7703 {
7704 // parse if let expr (required)
7705 std::unique_ptr<AST::IfLetExpr> if_let_expr
7706 = parse_if_let_expr ();
7707 if (if_let_expr == nullptr)
7708 {
7709 Error error (lexer.peek_token ()->get_locus (),
7710 "failed to parse (else) if let expression "
7711 "after if expression");
7712 add_error (std::move (error));
7713
7714 // skip somewhere?
7715 return nullptr;
7716 }
7717
d88234af
OA
7718 return std::unique_ptr<AST::IfExprConseqElse> (
7719 new AST::IfExprConseqElse (std::move (condition),
7720 std::move (if_body),
7721 std::move (if_let_expr),
7722 std::move (outer_attrs), locus));
32c8fb0e
JP
7723 }
7724 else
7725 {
7726 // parse if expr (required)
7727 std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr ();
7728 if (if_expr == nullptr)
7729 {
7730 Error error (lexer.peek_token ()->get_locus (),
7731 "failed to parse (else) if expression after "
7732 "if expression");
7733 add_error (std::move (error));
7734
7735 // skip somewhere?
7736 return nullptr;
7737 }
7738
d88234af
OA
7739 return std::unique_ptr<AST::IfExprConseqElse> (
7740 new AST::IfExprConseqElse (std::move (condition),
7741 std::move (if_body),
7742 std::move (if_expr),
7743 std::move (outer_attrs), locus));
32c8fb0e
JP
7744 }
7745 }
7746 default:
7747 // error - invalid token
7748 add_error (Error (t->get_locus (),
7749 "unexpected token %qs after else in if expression",
7750 t->get_token_description ()));
7751
7752 // skip somewhere?
7753 return nullptr;
7754 }
7755 }
7756}
7757
7758/* Parses an if let expression of any kind, including with else, else if, else
7759 * if let, and none. Note that any outer attributes will be ignored as if let
7760 * expressions don't support them. */
7761template <typename ManagedTokenSource>
7762std::unique_ptr<AST::IfLetExpr>
7763Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs,
80c68893 7764 location_t pratt_parsed_loc)
32c8fb0e
JP
7765{
7766 // TODO: make having outer attributes an error?
d991a3f1 7767 location_t locus = pratt_parsed_loc;
e5f3ad0f 7768 if (locus == UNKNOWN_LOCATION)
32c8fb0e
JP
7769 {
7770 locus = lexer.peek_token ()->get_locus ();
7771 if (!skip_token (IF))
7772 {
7773 skip_after_end_block ();
7774 return nullptr;
7775 }
7776 }
7777
7778 // detect accidental if expr parsed as if let expr
7779 if (lexer.peek_token ()->get_id () != LET)
7780 {
7781 Error error (lexer.peek_token ()->get_locus (),
7782 "if expression probably exists, but is being parsed as an "
7783 "if let expression. This may be a parser error");
7784 add_error (std::move (error));
7785
7786 // skip somewhere?
7787 return nullptr;
7788 }
7789 lexer.skip_token ();
7790
7791 // parse match arm patterns (which are required)
7792 std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns
7793 = parse_match_arm_patterns (EQUAL);
7794 if (match_arm_patterns.empty ())
7795 {
7796 Error error (
7797 lexer.peek_token ()->get_locus (),
7798 "failed to parse any match arm patterns in if let expression");
7799 add_error (std::move (error));
7800
7801 // skip somewhere?
7802 return nullptr;
7803 }
7804
7805 if (!skip_token (EQUAL))
7806 {
7807 // skip somewhere?
7808 return nullptr;
7809 }
7810
7811 // parse expression (required) - HACK to prevent struct expr being parsed
7812 ParseRestrictions no_struct_expr;
7813 no_struct_expr.can_be_struct_expr = false;
7814 std::unique_ptr<AST::Expr> scrutinee_expr = parse_expr ({}, no_struct_expr);
7815 if (scrutinee_expr == nullptr)
7816 {
7817 Error error (lexer.peek_token ()->get_locus (),
7818 "failed to parse scrutinee expression in if let expression");
7819 add_error (std::move (error));
7820
7821 // skip somewhere?
7822 return nullptr;
7823 }
7824 /* TODO: check for expression not being a struct expression or lazy boolean
7825 * expression here? or actually probably in semantic analysis. */
7826
7827 // parse block expression (required)
7828 std::unique_ptr<AST::BlockExpr> if_let_body = parse_block_expr ();
7829 if (if_let_body == nullptr)
7830 {
7831 Error error (
7832 lexer.peek_token ()->get_locus (),
7833 "failed to parse if let body block expression in if let expression");
7834 add_error (std::move (error));
7835
7836 // skip somewhere?
7837 return nullptr;
7838 }
7839
7840 // branch to parse end or else (and then else, else if, or else if let)
7841 if (lexer.peek_token ()->get_id () != ELSE)
7842 {
7843 // single selection - end of if let expression
7844 return std::unique_ptr<AST::IfLetExpr> (
7845 new AST::IfLetExpr (std::move (match_arm_patterns),
7846 std::move (scrutinee_expr), std::move (if_let_body),
7847 std::move (outer_attrs), locus));
7848 }
7849 else
7850 {
7851 // double or multiple selection - branch on end, else if, or else if let
7852
7853 // skip "else"
7854 lexer.skip_token ();
7855
7856 // branch on whether next token is '{' or 'if'
7857 const_TokenPtr t = lexer.peek_token ();
7858 switch (t->get_id ())
7859 {
7860 case LEFT_CURLY: {
7861 // double selection - else
7862 // parse else block expr (required)
7863 std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr ();
7864 if (else_body == nullptr)
7865 {
7866 Error error (lexer.peek_token ()->get_locus (),
7867 "failed to parse else body block expression in "
7868 "if let expression");
7869 add_error (std::move (error));
7870
7871 // skip somewhere?
7872 return nullptr;
7873 }
7874
7875 return std::unique_ptr<AST::IfLetExprConseqElse> (
7876 new AST::IfLetExprConseqElse (std::move (match_arm_patterns),
7877 std::move (scrutinee_expr),
7878 std::move (if_let_body),
7879 std::move (else_body),
7880 std::move (outer_attrs), locus));
7881 }
7882 case IF: {
7883 // multiple selection - else if or else if let
7884 // branch on whether next token is 'let' or not
7885 if (lexer.peek_token (1)->get_id () == LET)
7886 {
7887 // parse if let expr (required)
7888 std::unique_ptr<AST::IfLetExpr> if_let_expr
7889 = parse_if_let_expr ();
7890 if (if_let_expr == nullptr)
7891 {
7892 Error error (lexer.peek_token ()->get_locus (),
7893 "failed to parse (else) if let expression "
7894 "after if let expression");
7895 add_error (std::move (error));
7896
7897 // skip somewhere?
7898 return nullptr;
7899 }
7900
f2df348d
OA
7901 return std::unique_ptr<AST::IfLetExprConseqElse> (
7902 new AST::IfLetExprConseqElse (
32c8fb0e
JP
7903 std::move (match_arm_patterns), std::move (scrutinee_expr),
7904 std::move (if_let_body), std::move (if_let_expr),
7905 std::move (outer_attrs), locus));
7906 }
7907 else
7908 {
7909 // parse if expr (required)
7910 std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr ();
7911 if (if_expr == nullptr)
7912 {
7913 Error error (lexer.peek_token ()->get_locus (),
7914 "failed to parse (else) if expression after "
7915 "if let expression");
7916 add_error (std::move (error));
7917
7918 // skip somewhere?
7919 return nullptr;
7920 }
7921
f2df348d
OA
7922 return std::unique_ptr<AST::IfLetExprConseqElse> (
7923 new AST::IfLetExprConseqElse (
7924 std::move (match_arm_patterns), std::move (scrutinee_expr),
7925 std::move (if_let_body), std::move (if_expr),
7926 std::move (outer_attrs), locus));
32c8fb0e
JP
7927 }
7928 }
7929 default:
7930 // error - invalid token
7931 add_error (
7932 Error (t->get_locus (),
7933 "unexpected token %qs after else in if let expression",
7934 t->get_token_description ()));
7935
7936 // skip somewhere?
7937 return nullptr;
7938 }
7939 }
7940}
7941
7942/* TODO: possibly decide on different method of handling label (i.e. not
7943 * parameter) */
7944
7945/* Parses a "loop" infinite loop expression. Label is not parsed and should be
7946 * parsed via parse_labelled_loop_expr, which would call this. */
7947template <typename ManagedTokenSource>
7948std::unique_ptr<AST::LoopExpr>
7949Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs,
ff04ba26 7950 tl::optional<AST::LoopLabel> label,
80c68893 7951 location_t pratt_parsed_loc)
32c8fb0e 7952{
d991a3f1 7953 location_t locus = pratt_parsed_loc;
e5f3ad0f 7954 if (locus == UNKNOWN_LOCATION)
32c8fb0e 7955 {
ff04ba26
PEP
7956 if (label)
7957 locus = label->get_locus ();
32c8fb0e 7958 else
ff04ba26 7959 locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
7960
7961 if (!skip_token (LOOP))
7962 {
7963 skip_after_end_block ();
7964 return nullptr;
7965 }
7966 }
7967 else
7968 {
ff04ba26
PEP
7969 if (label)
7970 locus = label->get_locus ();
32c8fb0e
JP
7971 }
7972
7973 // parse loop body, which is required
7974 std::unique_ptr<AST::BlockExpr> loop_body = parse_block_expr ();
7975 if (loop_body == nullptr)
7976 {
7977 Error error (lexer.peek_token ()->get_locus (),
7978 "could not parse loop body in (infinite) loop expression");
7979 add_error (std::move (error));
7980
7981 return nullptr;
7982 }
7983
7984 return std::unique_ptr<AST::LoopExpr> (
7985 new AST::LoopExpr (std::move (loop_body), locus, std::move (label),
7986 std::move (outer_attrs)));
7987}
7988
7989/* Parses a "while" loop expression. Label is not parsed and should be parsed
7990 * via parse_labelled_loop_expr, which would call this. */
7991template <typename ManagedTokenSource>
7992std::unique_ptr<AST::WhileLoopExpr>
ff04ba26
PEP
7993Parser<ManagedTokenSource>::parse_while_loop_expr (
7994 AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label,
7995 location_t pratt_parsed_loc)
32c8fb0e 7996{
d991a3f1 7997 location_t locus = pratt_parsed_loc;
e5f3ad0f 7998 if (locus == UNKNOWN_LOCATION)
32c8fb0e 7999 {
ff04ba26
PEP
8000 if (label)
8001 locus = label->get_locus ();
32c8fb0e 8002 else
ff04ba26 8003 locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
8004
8005 if (!skip_token (WHILE))
8006 {
8007 skip_after_end_block ();
8008 return nullptr;
8009 }
8010 }
8011 else
8012 {
ff04ba26
PEP
8013 if (label)
8014 locus = label->get_locus ();
32c8fb0e
JP
8015 }
8016
8017 // ensure it isn't a while let loop
8018 if (lexer.peek_token ()->get_id () == LET)
8019 {
8020 Error error (lexer.peek_token ()->get_locus (),
8021 "appears to be while let loop but is being parsed by "
8022 "while loop - this may be a compiler issue");
8023 add_error (std::move (error));
8024
8025 // skip somewhere?
8026 return nullptr;
8027 }
8028
8029 // parse loop predicate (required) with HACK to prevent struct expr parsing
8030 ParseRestrictions no_struct_expr;
8031 no_struct_expr.can_be_struct_expr = false;
8032 std::unique_ptr<AST::Expr> predicate = parse_expr ({}, no_struct_expr);
8033 if (predicate == nullptr)
8034 {
8035 Error error (lexer.peek_token ()->get_locus (),
8036 "failed to parse predicate expression in while loop");
8037 add_error (std::move (error));
8038
8039 // skip somewhere?
8040 return nullptr;
8041 }
8042 /* TODO: check that it isn't struct expression here? actually, probably in
8043 * semantic analysis */
8044
8045 // parse loop body (required)
8046 std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
8047 if (body == nullptr)
8048 {
8049 Error error (lexer.peek_token ()->get_locus (),
8050 "failed to parse loop body block expression in while loop");
8051 add_error (std::move (error));
8052
8053 // skip somewhere
8054 return nullptr;
8055 }
8056
8057 return std::unique_ptr<AST::WhileLoopExpr> (
8058 new AST::WhileLoopExpr (std::move (predicate), std::move (body), locus,
8059 std::move (label), std::move (outer_attrs)));
8060}
8061
8062/* Parses a "while let" loop expression. Label is not parsed and should be
8063 * parsed via parse_labelled_loop_expr, which would call this. */
8064template <typename ManagedTokenSource>
8065std::unique_ptr<AST::WhileLetLoopExpr>
ff04ba26
PEP
8066Parser<ManagedTokenSource>::parse_while_let_loop_expr (
8067 AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label)
32c8fb0e 8068{
d991a3f1 8069 location_t locus = UNKNOWN_LOCATION;
ff04ba26
PEP
8070 if (label)
8071 locus = label->get_locus ();
32c8fb0e 8072 else
ff04ba26 8073 locus = lexer.peek_token ()->get_locus ();
e6ff2bcc 8074 maybe_skip_token (WHILE);
32c8fb0e
JP
8075
8076 /* check for possible accidental recognition of a while loop as a while let
8077 * loop */
8078 if (lexer.peek_token ()->get_id () != LET)
8079 {
8080 Error error (lexer.peek_token ()->get_locus (),
8081 "appears to be a while loop but is being parsed by "
8082 "while let loop - this may be a compiler issue");
8083 add_error (std::move (error));
8084
8085 // skip somewhere
8086 return nullptr;
8087 }
8088 // as this token is definitely let now, save the computation of comparison
8089 lexer.skip_token ();
8090
8091 // parse predicate patterns
8092 std::vector<std::unique_ptr<AST::Pattern>> predicate_patterns
8093 = parse_match_arm_patterns (EQUAL);
8094 // TODO: have to ensure that there is at least 1 pattern?
8095
8096 if (!skip_token (EQUAL))
8097 {
8098 // skip somewhere?
8099 return nullptr;
8100 }
8101
8102 /* parse predicate expression, which is required (and HACK to prevent struct
8103 * expr) */
8104 ParseRestrictions no_struct_expr;
8105 no_struct_expr.can_be_struct_expr = false;
8106 std::unique_ptr<AST::Expr> predicate_expr = parse_expr ({}, no_struct_expr);
8107 if (predicate_expr == nullptr)
8108 {
8109 Error error (lexer.peek_token ()->get_locus (),
8110 "failed to parse predicate expression in while let loop");
8111 add_error (std::move (error));
8112
8113 // skip somewhere?
8114 return nullptr;
8115 }
8116 /* TODO: ensure that struct expression is not parsed? Actually, probably in
8117 * semantic analysis. */
8118
8119 // parse loop body, which is required
8120 std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
8121 if (body == nullptr)
8122 {
8123 Error error (lexer.peek_token ()->get_locus (),
8124 "failed to parse block expr (loop body) of while let loop");
8125 add_error (std::move (error));
8126
8127 // skip somewhere?
8128 return nullptr;
8129 }
8130
8131 return std::unique_ptr<AST::WhileLetLoopExpr> (new AST::WhileLetLoopExpr (
8132 std::move (predicate_patterns), std::move (predicate_expr),
8133 std::move (body), locus, std::move (label), std::move (outer_attrs)));
8134}
8135
8136/* Parses a "for" iterative loop. Label is not parsed and should be parsed via
8137 * parse_labelled_loop_expr, which would call this. */
8138template <typename ManagedTokenSource>
8139std::unique_ptr<AST::ForLoopExpr>
ff04ba26
PEP
8140Parser<ManagedTokenSource>::parse_for_loop_expr (
8141 AST::AttrVec outer_attrs, tl::optional<AST::LoopLabel> label)
32c8fb0e 8142{
d991a3f1 8143 location_t locus = UNKNOWN_LOCATION;
ff04ba26
PEP
8144 if (label)
8145 locus = label->get_locus ();
32c8fb0e 8146 else
ff04ba26 8147 locus = lexer.peek_token ()->get_locus ();
48408712 8148 maybe_skip_token (FOR);
32c8fb0e
JP
8149
8150 // parse pattern, which is required
8151 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
8152 if (pattern == nullptr)
8153 {
8154 Error error (lexer.peek_token ()->get_locus (),
8155 "failed to parse iterator pattern in for loop");
8156 add_error (std::move (error));
8157
8158 // skip somewhere?
8159 return nullptr;
8160 }
8161
8162 if (!skip_token (IN))
8163 {
8164 // skip somewhere?
8165 return nullptr;
8166 }
8167
8168 /* parse iterator expression, which is required - also HACK to prevent
8169 * struct expr */
8170 ParseRestrictions no_struct_expr;
8171 no_struct_expr.can_be_struct_expr = false;
8172 std::unique_ptr<AST::Expr> expr = parse_expr ({}, no_struct_expr);
8173 if (expr == nullptr)
8174 {
8175 Error error (lexer.peek_token ()->get_locus (),
8176 "failed to parse iterator expression in for loop");
8177 add_error (std::move (error));
8178
8179 // skip somewhere?
8180 return nullptr;
8181 }
8182 // TODO: check to ensure this isn't struct expr? Or in semantic analysis.
8183
8184 // parse loop body, which is required
8185 std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
8186 if (body == nullptr)
8187 {
8188 Error error (lexer.peek_token ()->get_locus (),
8189 "failed to parse loop body block expression in for loop");
8190 add_error (std::move (error));
8191
8192 // skip somewhere?
8193 return nullptr;
8194 }
8195
8196 return std::unique_ptr<AST::ForLoopExpr> (
8197 new AST::ForLoopExpr (std::move (pattern), std::move (expr),
8198 std::move (body), locus, std::move (label),
8199 std::move (outer_attrs)));
8200}
8201
8202// Parses a loop expression with label (any kind of loop - disambiguates).
8203template <typename ManagedTokenSource>
3b1d27f7 8204std::unique_ptr<AST::Expr>
48408712
MJ
8205Parser<ManagedTokenSource>::parse_labelled_loop_expr (const_TokenPtr tok,
8206 AST::AttrVec outer_attrs)
32c8fb0e
JP
8207{
8208 /* TODO: decide whether it should not work if there is no label, or parse it
8209 * with no label at the moment, I will make it not work with no label
8210 * because that's the implication. */
8211
48408712 8212 if (tok->get_id () != LIFETIME)
32c8fb0e 8213 {
48408712 8214 Error error (tok->get_locus (),
32c8fb0e
JP
8215 "expected lifetime in labelled loop expr (to parse loop "
8216 "label) - found %qs",
48408712 8217 tok->get_token_description ());
32c8fb0e
JP
8218 add_error (std::move (error));
8219
8220 // skip?
8221 return nullptr;
8222 }
8223
8224 // parse loop label (required)
ff04ba26 8225 // TODO: Convert this return type to tl::expected instead of tl::optional
37908277
PEP
8226 auto parsed_label = parse_loop_label (tok);
8227 if (!parsed_label)
32c8fb0e
JP
8228 {
8229 Error error (lexer.peek_token ()->get_locus (),
8230 "failed to parse loop label in labelled loop expr");
8231 add_error (std::move (error));
8232
8233 // skip?
8234 return nullptr;
8235 }
8236
37908277
PEP
8237 auto label = parsed_label
8238 ? tl::optional<AST::LoopLabel> (parsed_label.value ())
8239 : tl::nullopt;
8240
32c8fb0e
JP
8241 // branch on next token
8242 const_TokenPtr t = lexer.peek_token ();
8243 switch (t->get_id ())
8244 {
8245 case LOOP:
8246 return parse_loop_expr (std::move (outer_attrs), std::move (label));
8247 case FOR:
8248 return parse_for_loop_expr (std::move (outer_attrs), std::move (label));
8249 case WHILE:
8250 // further disambiguate into while vs while let
8251 if (lexer.peek_token (1)->get_id () == LET)
8252 {
8253 return parse_while_let_loop_expr (std::move (outer_attrs),
8254 std::move (label));
8255 }
8256 else
8257 {
8258 return parse_while_loop_expr (std::move (outer_attrs),
8259 std::move (label));
8260 }
3b1d27f7
JD
8261 case LEFT_CURLY:
8262 return parse_block_expr (std::move (outer_attrs), std::move (label));
32c8fb0e
JP
8263 default:
8264 // error
8265 add_error (Error (t->get_locus (),
8266 "unexpected token %qs when parsing labelled loop",
8267 t->get_token_description ()));
8268
8269 // skip?
8270 return nullptr;
8271 }
8272}
8273
8274// Parses a match expression.
8275template <typename ManagedTokenSource>
8276std::unique_ptr<AST::MatchExpr>
8277Parser<ManagedTokenSource>::parse_match_expr (AST::AttrVec outer_attrs,
80c68893 8278 location_t pratt_parsed_loc)
32c8fb0e 8279{
d991a3f1 8280 location_t locus = pratt_parsed_loc;
e5f3ad0f 8281 if (locus == UNKNOWN_LOCATION)
32c8fb0e
JP
8282 {
8283 locus = lexer.peek_token ()->get_locus ();
7f631967 8284 skip_token (MATCH_KW);
32c8fb0e
JP
8285 }
8286
8287 /* parse scrutinee expression, which is required (and HACK to prevent struct
8288 * expr) */
8289 ParseRestrictions no_struct_expr;
8290 no_struct_expr.can_be_struct_expr = false;
8291 std::unique_ptr<AST::Expr> scrutinee = parse_expr ({}, no_struct_expr);
8292 if (scrutinee == nullptr)
8293 {
8294 Error error (lexer.peek_token ()->get_locus (),
8295 "failed to parse scrutinee expression in match expression");
8296 add_error (std::move (error));
8297
8298 // skip somewhere?
8299 return nullptr;
8300 }
8301 /* TODO: check for scrutinee expr not being struct expr? or do so in
8302 * semantic analysis */
8303
8304 if (!skip_token (LEFT_CURLY))
8305 {
8306 // skip somewhere?
8307 return nullptr;
8308 }
8309
8310 // parse inner attributes (if they exist)
8311 AST::AttrVec inner_attrs = parse_inner_attributes ();
8312
8313 // parse match arms (if they exist)
8314 // std::vector<std::unique_ptr<AST::MatchCase> > match_arms;
8315 std::vector<AST::MatchCase> match_arms;
8316
8317 // parse match cases
8318 while (lexer.peek_token ()->get_id () != RIGHT_CURLY)
8319 {
8320 // parse match arm itself, which is required
8321 AST::MatchArm arm = parse_match_arm ();
8322 if (arm.is_error ())
8323 {
8324 // TODO is this worth throwing everything away?
8325 Error error (lexer.peek_token ()->get_locus (),
8326 "failed to parse match arm in match arms");
8327 add_error (std::move (error));
8328
8329 return nullptr;
8330 }
8331
8332 if (!skip_token (MATCH_ARROW))
8333 {
8334 // skip after somewhere?
8335 // TODO is returning here a good idea? or is break better?
8336 return nullptr;
8337 }
8338
8339 ParseRestrictions restrictions;
8340 restrictions.expr_can_be_stmt = true;
32c8fb0e 8341
48408712 8342 std::unique_ptr<AST::Expr> expr = parse_expr ({}, restrictions);
9e9ee593 8343
48408712 8344 if (expr == nullptr)
32c8fb0e
JP
8345 {
8346 Error error (lexer.peek_token ()->get_locus (),
8347 "failed to parse expr in match arm in match expr");
8348 add_error (std::move (error));
8349
8350 // skip somewhere?
8351 return nullptr;
8352 }
32c8fb0e 8353
48408712 8354 bool is_expr_without_block = expr->is_expr_without_block ();
32c8fb0e 8355
9e9ee593 8356 match_arms.push_back (AST::MatchCase (std::move (arm), std::move (expr)));
32c8fb0e
JP
8357
8358 // handle comma presence
8359 if (lexer.peek_token ()->get_id () != COMMA)
8360 {
8361 if (!is_expr_without_block)
8362 {
8363 // allowed even if not final case
8364 continue;
8365 }
8366 else if (is_expr_without_block
8367 && lexer.peek_token ()->get_id () != RIGHT_CURLY)
8368 {
8369 // not allowed if not final case
8370 Error error (lexer.peek_token ()->get_locus (),
8371 "exprwithoutblock requires comma after match case "
8372 "expression in match arm (if not final case)");
8373 add_error (std::move (error));
8374
8375 return nullptr;
8376 }
8377 else
8378 {
8379 // otherwise, must be final case, so fine
8380 break;
8381 }
8382 }
8383 lexer.skip_token ();
8384 }
8385
8386 if (!skip_token (RIGHT_CURLY))
8387 {
8388 // skip somewhere?
8389 return nullptr;
8390 }
8391
8392 match_arms.shrink_to_fit ();
8393
8394 return std::unique_ptr<AST::MatchExpr> (
8395 new AST::MatchExpr (std::move (scrutinee), std::move (match_arms),
8396 std::move (inner_attrs), std::move (outer_attrs),
8397 locus));
8398}
8399
8400// Parses the "pattern" part of the match arm (the 'case x:' equivalent).
8401template <typename ManagedTokenSource>
8402AST::MatchArm
8403Parser<ManagedTokenSource>::parse_match_arm ()
8404{
8405 // parse optional outer attributes
8406 AST::AttrVec outer_attrs = parse_outer_attributes ();
8407
8408 // DEBUG
8409 rust_debug ("about to start parsing match arm patterns");
8410
8411 // break early if find right curly
8412 if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
8413 {
8414 // not an error
8415 return AST::MatchArm::create_error ();
8416 }
8417
8418 // parse match arm patterns - at least 1 is required
8419 std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns
8420 = parse_match_arm_patterns (RIGHT_CURLY);
8421 if (match_arm_patterns.empty ())
8422 {
8423 Error error (lexer.peek_token ()->get_locus (),
8424 "failed to parse any patterns in match arm");
8425 add_error (std::move (error));
8426
8427 // skip somewhere?
8428 return AST::MatchArm::create_error ();
8429 }
8430
8431 // DEBUG
8432 rust_debug ("successfully parsed match arm patterns");
8433
8434 // parse match arm guard expr if it exists
8435 std::unique_ptr<AST::Expr> guard_expr = nullptr;
8436 if (lexer.peek_token ()->get_id () == IF)
8437 {
8438 lexer.skip_token ();
8439
8440 guard_expr = parse_expr ();
8441 if (guard_expr == nullptr)
8442 {
8443 Error error (lexer.peek_token ()->get_locus (),
8444 "failed to parse guard expression in match arm");
8445 add_error (std::move (error));
8446
8447 // skip somewhere?
8448 return AST::MatchArm::create_error ();
8449 }
8450 }
8451
8452 // DEBUG
8453 rust_debug ("successfully parsed match arm");
8454
8455 return AST::MatchArm (std::move (match_arm_patterns),
8456 lexer.peek_token ()->get_locus (),
8457 std::move (guard_expr), std::move (outer_attrs));
8458}
8459
8460/* Parses the patterns used in a match arm. End token id is the id of the
8461 * token that would exist after the patterns are done (e.g. '}' for match
8462 * expr, '=' for if let and while let). */
8463template <typename ManagedTokenSource>
8464std::vector<std::unique_ptr<AST::Pattern>>
8465Parser<ManagedTokenSource>::parse_match_arm_patterns (TokenId end_token_id)
8466{
8467 // skip optional leading '|'
8468 if (lexer.peek_token ()->get_id () == PIPE)
8469 lexer.skip_token ();
8470 /* TODO: do I even need to store the result of this? can't be used.
8471 * If semantically different, I need a wrapped "match arm patterns" object
8472 * for this. */
8473
8474 std::vector<std::unique_ptr<AST::Pattern>> patterns;
8475
8476 // quick break out if end_token_id
8477 if (lexer.peek_token ()->get_id () == end_token_id)
8478 return patterns;
8479
8480 // parse required pattern - if doesn't exist, return empty
8481 std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
8482 if (initial_pattern == nullptr)
8483 {
8484 // FIXME: should this be an error?
8485 return patterns;
8486 }
8487 patterns.push_back (std::move (initial_pattern));
8488
8489 // DEBUG
8490 rust_debug ("successfully parsed initial match arm pattern");
8491
8492 // parse new patterns as long as next char is '|'
8493 const_TokenPtr t = lexer.peek_token ();
8494 while (t->get_id () == PIPE)
8495 {
8496 // skip pipe token
8497 lexer.skip_token ();
8498
8499 // break if hit end token id
8500 if (lexer.peek_token ()->get_id () == end_token_id)
8501 break;
8502
8503 // parse pattern
8504 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
8505 if (pattern == nullptr)
8506 {
8507 // this is an error
8508 Error error (lexer.peek_token ()->get_locus (),
8509 "failed to parse pattern in match arm patterns");
8510 add_error (std::move (error));
8511
8512 // skip somewhere?
8513 return {};
8514 }
8515
8516 patterns.push_back (std::move (pattern));
8517
8518 t = lexer.peek_token ();
8519 }
8520
8521 patterns.shrink_to_fit ();
8522
8523 return patterns;
8524}
8525
8526// Parses an async block expression.
8527template <typename ManagedTokenSource>
8528std::unique_ptr<AST::AsyncBlockExpr>
8529Parser<ManagedTokenSource>::parse_async_block_expr (AST::AttrVec outer_attrs)
8530{
d991a3f1 8531 location_t locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
8532 skip_token (ASYNC);
8533
8534 // detect optional move token
8535 bool has_move = false;
8536 if (lexer.peek_token ()->get_id () == MOVE)
8537 {
8538 lexer.skip_token ();
8539 has_move = true;
8540 }
8541
8542 // parse block expression (required)
8543 std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
8544 if (block_expr == nullptr)
8545 {
8546 Error error (
8547 lexer.peek_token ()->get_locus (),
8548 "failed to parse block expression of async block expression");
8549 add_error (std::move (error));
8550
8551 // skip somewhere?
8552 return nullptr;
8553 }
8554
8555 return std::unique_ptr<AST::AsyncBlockExpr> (
8556 new AST::AsyncBlockExpr (std::move (block_expr), has_move,
8557 std::move (outer_attrs), locus));
8558}
8559
8560// Parses an unsafe block expression.
8561template <typename ManagedTokenSource>
8562std::unique_ptr<AST::UnsafeBlockExpr>
80c68893
OA
8563Parser<ManagedTokenSource>::parse_unsafe_block_expr (
8564 AST::AttrVec outer_attrs, location_t pratt_parsed_loc)
32c8fb0e 8565{
d991a3f1 8566 location_t locus = pratt_parsed_loc;
e5f3ad0f 8567 if (locus == UNKNOWN_LOCATION)
32c8fb0e
JP
8568 {
8569 locus = lexer.peek_token ()->get_locus ();
8570 skip_token (UNSAFE);
8571 }
8572
8573 // parse block expression (required)
8574 std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
8575 if (block_expr == nullptr)
8576 {
8577 Error error (
8578 lexer.peek_token ()->get_locus (),
8579 "failed to parse block expression of unsafe block expression");
8580 add_error (std::move (error));
8581
8582 // skip somewhere?
8583 return nullptr;
8584 }
8585
8586 return std::unique_ptr<AST::UnsafeBlockExpr> (
8587 new AST::UnsafeBlockExpr (std::move (block_expr), std::move (outer_attrs),
8588 locus));
8589}
8590
8591// Parses an array definition expression.
8592template <typename ManagedTokenSource>
8593std::unique_ptr<AST::ArrayExpr>
8594Parser<ManagedTokenSource>::parse_array_expr (AST::AttrVec outer_attrs,
80c68893 8595 location_t pratt_parsed_loc)
32c8fb0e 8596{
d991a3f1 8597 location_t locus = pratt_parsed_loc;
e5f3ad0f 8598 if (locus == UNKNOWN_LOCATION)
32c8fb0e
JP
8599 {
8600 locus = lexer.peek_token ()->get_locus ();
8601 skip_token (LEFT_SQUARE);
8602 }
8603
8604 // parse optional inner attributes
8605 AST::AttrVec inner_attrs = parse_inner_attributes ();
8606
8607 // parse the "array elements" section, which is optional
8608 if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
8609 {
8610 // no array elements
8611 lexer.skip_token ();
8612
8613 std::vector<std::unique_ptr<AST::Expr>> exprs;
8614 auto array_elems
c8721ccd
OA
8615 = std::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus);
8616 return std::make_unique<AST::ArrayExpr> (std::move (array_elems),
8617 std::move (inner_attrs),
8618 std::move (outer_attrs), locus);
32c8fb0e
JP
8619 }
8620 else
8621 {
8622 // should have array elements
8623 // parse initial expression, which is required for either
8624 std::unique_ptr<AST::Expr> initial_expr = parse_expr ();
8625 if (initial_expr == nullptr)
8626 {
8627 Error error (lexer.peek_token ()->get_locus (),
8628 "could not parse expression in array expression "
8629 "(even though arrayelems seems to be present)");
8630 add_error (std::move (error));
8631
8632 // skip somewhere?
8633 return nullptr;
8634 }
8635
8636 if (lexer.peek_token ()->get_id () == SEMICOLON)
8637 {
8638 // copy array elems
8639 lexer.skip_token ();
8640
8641 // parse copy amount expression (required)
8642 std::unique_ptr<AST::Expr> copy_amount = parse_expr ();
8643 if (copy_amount == nullptr)
8644 {
8645 Error error (lexer.peek_token ()->get_locus (),
8646 "could not parse copy amount expression in array "
8647 "expression (arrayelems)");
8648 add_error (std::move (error));
8649
8650 // skip somewhere?
8651 return nullptr;
8652 }
8653
8654 skip_token (RIGHT_SQUARE);
8655
8656 std::unique_ptr<AST::ArrayElemsCopied> copied_array_elems (
8657 new AST::ArrayElemsCopied (std::move (initial_expr),
8658 std::move (copy_amount), locus));
8659 return std::unique_ptr<AST::ArrayExpr> (
8660 new AST::ArrayExpr (std::move (copied_array_elems),
8661 std::move (inner_attrs),
8662 std::move (outer_attrs), locus));
8663 }
8664 else if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
8665 {
8666 // single-element array expression
8667 std::vector<std::unique_ptr<AST::Expr>> exprs;
8668 exprs.reserve (1);
8669 exprs.push_back (std::move (initial_expr));
8670 exprs.shrink_to_fit ();
8671
8672 skip_token (RIGHT_SQUARE);
8673
8674 std::unique_ptr<AST::ArrayElemsValues> array_elems (
8675 new AST::ArrayElemsValues (std::move (exprs), locus));
8676 return std::unique_ptr<AST::ArrayExpr> (
8677 new AST::ArrayExpr (std::move (array_elems),
8678 std::move (inner_attrs),
8679 std::move (outer_attrs), locus));
8680 }
8681 else if (lexer.peek_token ()->get_id () == COMMA)
8682 {
8683 // multi-element array expression (or trailing comma)
8684 std::vector<std::unique_ptr<AST::Expr>> exprs;
8685 exprs.push_back (std::move (initial_expr));
8686
8687 const_TokenPtr t = lexer.peek_token ();
8688 while (t->get_id () == COMMA)
8689 {
8690 lexer.skip_token ();
8691
8692 // quick break if right square bracket
8693 if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
8694 break;
8695
8696 // parse expression (required)
8697 std::unique_ptr<AST::Expr> expr = parse_expr ();
8698 if (expr == nullptr)
8699 {
8700 Error error (lexer.peek_token ()->get_locus (),
8701 "failed to parse element in array expression");
8702 add_error (std::move (error));
8703
8704 // skip somewhere?
8705 return nullptr;
8706 }
8707 exprs.push_back (std::move (expr));
8708
8709 t = lexer.peek_token ();
8710 }
8711
8712 skip_token (RIGHT_SQUARE);
8713
8714 exprs.shrink_to_fit ();
8715
8716 std::unique_ptr<AST::ArrayElemsValues> array_elems (
8717 new AST::ArrayElemsValues (std::move (exprs), locus));
8718 return std::unique_ptr<AST::ArrayExpr> (
8719 new AST::ArrayExpr (std::move (array_elems),
8720 std::move (inner_attrs),
8721 std::move (outer_attrs), locus));
8722 }
8723 else
8724 {
8725 // error
8726 Error error (lexer.peek_token ()->get_locus (),
8727 "unexpected token %qs in array expression (arrayelems)",
8728 lexer.peek_token ()->get_token_description ());
8729 add_error (std::move (error));
8730
8731 // skip somewhere?
8732 return nullptr;
8733 }
8734 }
8735}
8736
8737// Parses a single parameter used in a closure definition.
8738template <typename ManagedTokenSource>
8739AST::ClosureParam
8740Parser<ManagedTokenSource>::parse_closure_param ()
8741{
8742 AST::AttrVec outer_attrs = parse_outer_attributes ();
8743
8744 // parse pattern (which is required)
24ce9baa 8745 std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
32c8fb0e
JP
8746 if (pattern == nullptr)
8747 {
8748 // not necessarily an error
8749 return AST::ClosureParam::create_error ();
8750 }
8751
8752 // parse optional type of param
8753 std::unique_ptr<AST::Type> type = nullptr;
8754 if (lexer.peek_token ()->get_id () == COLON)
8755 {
8756 lexer.skip_token ();
8757
8758 // parse type, which is now required
8759 type = parse_type ();
8760 if (type == nullptr)
8761 {
8762 Error error (lexer.peek_token ()->get_locus (),
8763 "failed to parse type in closure parameter");
8764 add_error (std::move (error));
8765
8766 // skip somewhere?
8767 return AST::ClosureParam::create_error ();
8768 }
8769 }
8770
80c68893 8771 location_t loc = pattern->get_locus ();
95dc1147
JJ
8772 return AST::ClosureParam (std::move (pattern), loc, std::move (type),
8773 std::move (outer_attrs));
32c8fb0e
JP
8774}
8775
8776// Parses a grouped or tuple expression (disambiguates).
8777template <typename ManagedTokenSource>
8778std::unique_ptr<AST::ExprWithoutBlock>
8779Parser<ManagedTokenSource>::parse_grouped_or_tuple_expr (
80c68893 8780 AST::AttrVec outer_attrs, location_t pratt_parsed_loc)
32c8fb0e
JP
8781{
8782 // adjustment to allow Pratt parsing to reuse function without copy-paste
d991a3f1 8783 location_t locus = pratt_parsed_loc;
e5f3ad0f 8784 if (locus == UNKNOWN_LOCATION)
32c8fb0e
JP
8785 {
8786 locus = lexer.peek_token ()->get_locus ();
8787 skip_token (LEFT_PAREN);
8788 }
8789
8790 // parse optional inner attributes
8791 AST::AttrVec inner_attrs = parse_inner_attributes ();
8792
8793 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
8794 {
8795 // must be empty tuple
8796 lexer.skip_token ();
8797
8798 // create tuple with empty tuple elems
8799 return std::unique_ptr<AST::TupleExpr> (
8800 new AST::TupleExpr (std::vector<std::unique_ptr<AST::Expr>> (),
8801 std::move (inner_attrs), std::move (outer_attrs),
8802 locus));
8803 }
8804
8805 // parse first expression (required)
8806 std::unique_ptr<AST::Expr> first_expr = parse_expr ();
8807 if (first_expr == nullptr)
8808 {
8809 Error error (lexer.peek_token ()->get_locus (),
8810 "failed to parse expression in grouped or tuple expression");
8811 add_error (std::move (error));
8812
8813 // skip after somewhere?
8814 return nullptr;
8815 }
8816
8817 // detect whether grouped expression with right parentheses as next token
8818 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
8819 {
8820 // must be grouped expr
8821 lexer.skip_token ();
8822
8823 // create grouped expr
8824 return std::unique_ptr<AST::GroupedExpr> (
8825 new AST::GroupedExpr (std::move (first_expr), std::move (inner_attrs),
8826 std::move (outer_attrs), locus));
8827 }
8828 else if (lexer.peek_token ()->get_id () == COMMA)
8829 {
8830 // tuple expr
8831 std::vector<std::unique_ptr<AST::Expr>> exprs;
8832 exprs.push_back (std::move (first_expr));
8833
8834 // parse potential other tuple exprs
8835 const_TokenPtr t = lexer.peek_token ();
8836 while (t->get_id () == COMMA)
8837 {
8838 lexer.skip_token ();
8839
8840 // break out if right paren
8841 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
8842 break;
8843
8844 // parse expr, which is now required
8845 std::unique_ptr<AST::Expr> expr = parse_expr ();
8846 if (expr == nullptr)
8847 {
8848 Error error (lexer.peek_token ()->get_locus (),
8849 "failed to parse expr in tuple expr");
8850 add_error (std::move (error));
8851
8852 // skip somewhere?
8853 return nullptr;
8854 }
8855 exprs.push_back (std::move (expr));
8856
8857 t = lexer.peek_token ();
8858 }
8859
8860 // skip right paren
8861 skip_token (RIGHT_PAREN);
8862
8863 return std::unique_ptr<AST::TupleExpr> (
8864 new AST::TupleExpr (std::move (exprs), std::move (inner_attrs),
8865 std::move (outer_attrs), locus));
8866 }
8867 else
8868 {
8869 // error
8870 const_TokenPtr t = lexer.peek_token ();
8871 Error error (t->get_locus (),
8872 "unexpected token %qs in grouped or tuple expression "
8873 "(parenthesised expression) - expected %<)%> for grouped "
8874 "expr and %<,%> for tuple expr",
8875 t->get_token_description ());
8876 add_error (std::move (error));
8877
8878 // skip somewhere?
8879 return nullptr;
8880 }
8881}
8882
8883// Parses a type (will further disambiguate any type).
8884template <typename ManagedTokenSource>
8885std::unique_ptr<AST::Type>
8886Parser<ManagedTokenSource>::parse_type (bool save_errors)
8887{
8888 /* rules for all types:
8889 * NeverType: '!'
8890 * SliceType: '[' Type ']'
8891 * InferredType: '_'
8892 * MacroInvocation: SimplePath '!' DelimTokenTree
8893 * ParenthesisedType: '(' Type ')'
8894 * ImplTraitType: 'impl' TypeParamBounds
8895 * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'?
8896 * TypeParamBound Lifetime | TraitBound
8897 * ImplTraitTypeOneBound: 'impl' TraitBound
8898 * TraitObjectType: 'dyn'? TypeParamBounds
8899 * TraitObjectTypeOneBound: 'dyn'? TraitBound
8900 * TraitBound '?'? ForLifetimes? TypePath | '(' '?'?
8901 * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes?
8902 * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
8903 * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )?
8904 * 'unsafe'?
8905 * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>'
8906 * (
8907 * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment (
8908 * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']'
8909 * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds
8910 * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds
8911 * TupleType: '(' Type etc. - regular tuple stuff. Also
8912 * regular tuple vs parenthesised precedence
8913 *
8914 * Disambiguate between macro and type path via type path being parsed, and
8915 * then if '!' found, convert type path to simple path for macro. Usual
8916 * disambiguation for tuple vs parenthesised. For ImplTraitType and
8917 * TraitObjectType individual disambiguations, they seem more like "special
8918 * cases", so probably just try to parse the more general ImplTraitType or
8919 * TraitObjectType and return OneBound versions if they satisfy those
8920 * criteria. */
8921
8922 const_TokenPtr t = lexer.peek_token ();
8923 switch (t->get_id ())
8924 {
8925 case EXCLAM:
8926 // never type - can't be macro as no path beforehand
8927 lexer.skip_token ();
8928 return std::unique_ptr<AST::NeverType> (
8929 new AST::NeverType (t->get_locus ()));
8930 case LEFT_SQUARE:
8931 // slice type or array type - requires further disambiguation
8932 return parse_slice_or_array_type ();
2a094010 8933 case LEFT_SHIFT:
32c8fb0e
JP
8934 case LEFT_ANGLE: {
8935 // qualified path in type
8936 AST::QualifiedPathInType path = parse_qualified_path_in_type ();
8937 if (path.is_error ())
8938 {
8939 if (save_errors)
8940 {
8941 Error error (t->get_locus (),
8942 "failed to parse qualified path in type");
8943 add_error (std::move (error));
8944 }
8945
8946 return nullptr;
8947 }
8948 return std::unique_ptr<AST::QualifiedPathInType> (
8949 new AST::QualifiedPathInType (std::move (path)));
8950 }
8951 case UNDERSCORE:
8952 // inferred type
8953 lexer.skip_token ();
8954 return std::unique_ptr<AST::InferredType> (
8955 new AST::InferredType (t->get_locus ()));
8956 case ASTERISK:
8957 // raw pointer type
8958 return parse_raw_pointer_type ();
8959 case AMP: // does this also include AMP_AMP?
9cbd2706 8960 case LOGICAL_AND:
32c8fb0e
JP
8961 // reference type
8962 return parse_reference_type ();
8963 case LIFETIME: {
8964 /* probably a lifetime bound, so probably type param bounds in
8965 * TraitObjectType */
8966 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
8967 = parse_type_param_bounds ();
8968
8969 return std::unique_ptr<AST::TraitObjectType> (
8970 new AST::TraitObjectType (std::move (bounds), t->get_locus (),
8971 false));
8972 }
8973 case IDENTIFIER:
8974 case SUPER:
8975 case SELF:
8976 case SELF_ALIAS:
8977 case CRATE:
8978 case DOLLAR_SIGN:
8979 case SCOPE_RESOLUTION: {
8980 // macro invocation or type path - requires further disambiguation.
8981 /* for parsing path component of each rule, perhaps parse it as a
8982 * typepath and attempt conversion to simplepath if a trailing '!' is
8983 * found */
8984 /* Type path also includes TraitObjectTypeOneBound BUT if it starts
8985 * with it, it is exactly the same as a TypePath syntactically, so
8986 * this is a syntactical ambiguity. As such, the parser will parse it
8987 * as a TypePath. This, however, does not prevent TraitObjectType from
8988 * starting with a typepath. */
8989
8990 // parse path as type path
8991 AST::TypePath path = parse_type_path ();
8992 if (path.is_error ())
8993 {
8994 if (save_errors)
8995 {
8996 Error error (t->get_locus (),
8997 "failed to parse path as first component of type");
8998 add_error (std::move (error));
8999 }
9000
9001 return nullptr;
9002 }
d991a3f1 9003 location_t locus = path.get_locus ();
32c8fb0e
JP
9004
9005 // branch on next token
9006 t = lexer.peek_token ();
9007 switch (t->get_id ())
9008 {
9009 case EXCLAM: {
9010 // macro invocation
9011 // convert to simple path
9012 AST::SimplePath macro_path = path.as_simple_path ();
9013 if (macro_path.is_empty ())
9014 {
9015 if (save_errors)
9016 {
9017 Error error (t->get_locus (),
9018 "failed to parse simple path in macro "
9019 "invocation (for type)");
9020 add_error (std::move (error));
9021 }
9022
9023 return nullptr;
9024 }
9025
9026 lexer.skip_token ();
9027
9028 AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
9029
51b607c2
AC
9030 return AST::MacroInvocation::Regular (
9031 AST::MacroInvocData (std::move (macro_path),
9032 std::move (tok_tree)),
9033 {}, locus);
32c8fb0e
JP
9034 }
9035 case PLUS: {
9036 // type param bounds
9037 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9038
9039 // convert type path to trait bound
9040 std::unique_ptr<AST::TraitBound> path_bound (
9041 new AST::TraitBound (std::move (path), locus, false, false));
9042 bounds.push_back (std::move (path_bound));
9043
9044 /* parse rest of bounds - FIXME: better way to find when to stop
9045 * parsing */
9046 while (t->get_id () == PLUS)
9047 {
9048 lexer.skip_token ();
9049
9050 // parse bound if it exists - if not, assume end of sequence
9051 std::unique_ptr<AST::TypeParamBound> bound
9052 = parse_type_param_bound ();
9053 if (bound == nullptr)
9054 {
9055 break;
9056 }
9057 bounds.push_back (std::move (bound));
9058
9059 t = lexer.peek_token ();
9060 }
9061
9062 return std::unique_ptr<AST::TraitObjectType> (
9063 new AST::TraitObjectType (std::move (bounds), locus, false));
9064 }
9065 default:
9066 // assume that this is a type path and not an error
9067 return std::unique_ptr<AST::TypePath> (
9068 new AST::TypePath (std::move (path)));
9069 }
9070 }
9071 case LEFT_PAREN:
9072 /* tuple type or parenthesised type - requires further disambiguation
9073 * (the usual). ok apparently can be a parenthesised TraitBound too, so
9074 * could be TraitObjectTypeOneBound or TraitObjectType */
9075 return parse_paren_prefixed_type ();
9076 case FOR:
9077 // TraitObjectTypeOneBound or BareFunctionType
9078 return parse_for_prefixed_type ();
9079 case ASYNC:
9080 case CONST:
9081 case UNSAFE:
7f631967
PEP
9082 case EXTERN_KW:
9083 case FN_KW:
32c8fb0e
JP
9084 // bare function type (with no for lifetimes)
9085 return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
9086 case IMPL:
9087 lexer.skip_token ();
9088 if (lexer.peek_token ()->get_id () == LIFETIME)
9089 {
9090 /* cannot be one bound because lifetime prevents it from being
9091 * traitbound */
9092 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
9093 = parse_type_param_bounds ();
9094
9095 return std::unique_ptr<AST::ImplTraitType> (
9096 new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
9097 }
9098 else
9099 {
9100 // should be trait bound, so parse trait bound
9101 std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
9102 if (initial_bound == nullptr)
9103 {
9104 if (save_errors)
9105 {
9106 Error error (lexer.peek_token ()->get_locus (),
9107 "failed to parse ImplTraitType initial bound");
9108 add_error (std::move (error));
9109 }
9110
9111 return nullptr;
9112 }
9113
d991a3f1 9114 location_t locus = t->get_locus ();
32c8fb0e
JP
9115
9116 // short cut if next token isn't '+'
9117 t = lexer.peek_token ();
9118 if (t->get_id () != PLUS)
9119 {
9120 // convert trait bound to value object
9121 AST::TraitBound value_bound (*initial_bound);
9122
9123 // DEBUG: removed as unique ptr, so should auto-delete
9124 // delete initial_bound;
9125
9126 return std::unique_ptr<AST::ImplTraitTypeOneBound> (
9127 new AST::ImplTraitTypeOneBound (std::move (value_bound),
9128 locus));
9129 }
9130
9131 // parse additional type param bounds
9132 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9133 bounds.push_back (std::move (initial_bound));
9134 while (t->get_id () == PLUS)
9135 {
9136 lexer.skip_token ();
9137
9138 // parse bound if it exists
9139 std::unique_ptr<AST::TypeParamBound> bound
9140 = parse_type_param_bound ();
9141 if (bound == nullptr)
9142 {
9143 // not an error as trailing plus may exist
9144 break;
9145 }
9146 bounds.push_back (std::move (bound));
9147
9148 t = lexer.peek_token ();
9149 }
9150
9151 return std::unique_ptr<AST::ImplTraitType> (
9152 new AST::ImplTraitType (std::move (bounds), locus));
9153 }
9154 case DYN:
9155 case QUESTION_MARK: {
9156 // either TraitObjectType or TraitObjectTypeOneBound
9157 bool has_dyn = false;
9158 if (t->get_id () == DYN)
9159 {
9160 lexer.skip_token ();
9161 has_dyn = true;
9162 }
9163
9164 if (lexer.peek_token ()->get_id () == LIFETIME)
9165 {
9166 /* cannot be one bound because lifetime prevents it from being
9167 * traitbound */
9168 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
9169 = parse_type_param_bounds ();
9170
9171 return std::unique_ptr<AST::TraitObjectType> (
9172 new AST::TraitObjectType (std::move (bounds), t->get_locus (),
9173 has_dyn));
9174 }
9175 else
9176 {
9177 // should be trait bound, so parse trait bound
9178 std::unique_ptr<AST::TraitBound> initial_bound
9179 = parse_trait_bound ();
9180 if (initial_bound == nullptr)
9181 {
9182 if (save_errors)
9183 {
9184 Error error (
9185 lexer.peek_token ()->get_locus (),
9186 "failed to parse TraitObjectType initial bound");
9187 add_error (std::move (error));
9188 }
9189
9190 return nullptr;
9191 }
9192
9193 // short cut if next token isn't '+'
9194 t = lexer.peek_token ();
9195 if (t->get_id () != PLUS)
9196 {
9197 // convert trait bound to value object
9198 AST::TraitBound value_bound (*initial_bound);
9199
9200 // DEBUG: removed as unique ptr, so should auto delete
9201 // delete initial_bound;
9202
9203 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
9204 new AST::TraitObjectTypeOneBound (std::move (value_bound),
9205 t->get_locus (), has_dyn));
9206 }
9207
9208 // parse additional type param bounds
9209 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9210 bounds.push_back (std::move (initial_bound));
9211 while (t->get_id () == PLUS)
9212 {
9213 lexer.skip_token ();
9214
9215 // parse bound if it exists
9216 std::unique_ptr<AST::TypeParamBound> bound
9217 = parse_type_param_bound ();
9218 if (bound == nullptr)
9219 {
9220 // not an error as trailing plus may exist
9221 break;
9222 }
9223 bounds.push_back (std::move (bound));
9224
9225 t = lexer.peek_token ();
9226 }
9227
9228 return std::unique_ptr<AST::TraitObjectType> (
9229 new AST::TraitObjectType (std::move (bounds), t->get_locus (),
9230 has_dyn));
9231 }
9232 }
9233 default:
9234 if (save_errors)
9235 add_error (Error (t->get_locus (), "unrecognised token %qs in type",
9236 t->get_token_description ()));
9237
9238 return nullptr;
9239 }
9240}
9241
9242/* Parses a type that has '(' as its first character. Returns a tuple type,
9243 * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
9244 * on following characters. */
9245template <typename ManagedTokenSource>
9246std::unique_ptr<AST::Type>
9247Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
9248{
9249 /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
9250 * a trait bound, not a parenthesised type, so that it can still be used in
9251 * type param bounds. */
9252
9253 /* NOTE: this implementation is really shit but I couldn't think of a better
9254 * one. It requires essentially breaking polymorphism and downcasting via
9255 * virtual method abuse, as it was copied from the rustc implementation (in
9256 * which types are reified due to tagged union), after a more OOP attempt by
9257 * me failed. */
80c68893 9258 location_t left_delim_locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
9259
9260 // skip left delim
9261 lexer.skip_token ();
9262 /* while next token isn't close delim, parse comma-separated types, saving
9263 * whether trailing comma happens */
9264 const_TokenPtr t = lexer.peek_token ();
9265 bool trailing_comma = true;
9266 std::vector<std::unique_ptr<AST::Type>> types;
9267
9268 while (t->get_id () != RIGHT_PAREN)
9269 {
9270 std::unique_ptr<AST::Type> type = parse_type ();
9271 if (type == nullptr)
9272 {
9273 Error error (t->get_locus (),
9274 "failed to parse type inside parentheses (probably "
9275 "tuple or parenthesised)");
9276 add_error (std::move (error));
9277
9278 return nullptr;
9279 }
9280 types.push_back (std::move (type));
9281
9282 t = lexer.peek_token ();
9283 if (t->get_id () != COMMA)
9284 {
9285 trailing_comma = false;
9286 break;
9287 }
9288 lexer.skip_token ();
9289
9290 t = lexer.peek_token ();
9291 }
9292
9293 if (!skip_token (RIGHT_PAREN))
9294 {
9295 return nullptr;
9296 }
9297
9298 // if only one type and no trailing comma, then not a tuple type
9299 if (types.size () == 1 && !trailing_comma)
9300 {
9301 // must be a TraitObjectType (with more than one bound)
9302 if (lexer.peek_token ()->get_id () == PLUS)
9303 {
9304 // create type param bounds vector
9305 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9306
9307 // HACK: convert type to traitbound and add to bounds
9308 std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
9309 std::unique_ptr<AST::TraitBound> converted_bound (
9310 released_ptr->to_trait_bound (true));
9311 if (converted_bound == nullptr)
9312 {
9313 Error error (
9314 lexer.peek_token ()->get_locus (),
9315 "failed to hackily converted parsed type to trait bound");
9316 add_error (std::move (error));
9317
9318 return nullptr;
9319 }
9320 bounds.push_back (std::move (converted_bound));
9321
9322 t = lexer.peek_token ();
9323 while (t->get_id () == PLUS)
9324 {
9325 lexer.skip_token ();
9326
9327 // attempt to parse typeparambound
9328 std::unique_ptr<AST::TypeParamBound> bound
9329 = parse_type_param_bound ();
9330 if (bound == nullptr)
9331 {
9332 // not an error if null
9333 break;
9334 }
9335 bounds.push_back (std::move (bound));
9336
9337 t = lexer.peek_token ();
9338 }
9339
9340 return std::unique_ptr<AST::TraitObjectType> (
9341 new AST::TraitObjectType (std::move (bounds), left_delim_locus,
9342 false));
9343 }
9344 else
9345 {
9346 // release vector pointer
9347 std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
9348 /* HACK: attempt to convert to trait bound. if fails, parenthesised
9349 * type */
9350 std::unique_ptr<AST::TraitBound> converted_bound (
9351 released_ptr->to_trait_bound (true));
9352 if (converted_bound == nullptr)
9353 {
9354 // parenthesised type
9355 return std::unique_ptr<AST::ParenthesisedType> (
9356 new AST::ParenthesisedType (std::move (released_ptr),
9357 left_delim_locus));
9358 }
9359 else
9360 {
9361 // trait object type (one bound)
9362
9363 // get value semantics trait bound
9364 AST::TraitBound value_bound (*converted_bound);
9365
9366 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
9367 new AST::TraitObjectTypeOneBound (value_bound,
9368 left_delim_locus));
9369 }
9370 }
9371 }
9372 else
9373 {
9374 return std::unique_ptr<AST::TupleType> (
9375 new AST::TupleType (std::move (types), left_delim_locus));
9376 }
9377 /* TODO: ensure that this ensures that dynamic dispatch for traits is not
9378 * lost somehow */
9379}
9380
9381/* Parses a type that has 'for' as its first character. This means it has a
9382 * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
9383 * TraitObjectTypeOneBound depending on following characters. */
9384template <typename ManagedTokenSource>
9385std::unique_ptr<AST::Type>
9386Parser<ManagedTokenSource>::parse_for_prefixed_type ()
9387{
80c68893 9388 location_t for_locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
9389 // parse for lifetimes in type
9390 std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
9391
9392 // branch on next token - either function or a trait type
9393 const_TokenPtr t = lexer.peek_token ();
9394 switch (t->get_id ())
9395 {
9396 case ASYNC:
9397 case CONST:
9398 case UNSAFE:
7f631967
PEP
9399 case EXTERN_KW:
9400 case FN_KW:
32c8fb0e
JP
9401 return parse_bare_function_type (std::move (for_lifetimes));
9402 case SCOPE_RESOLUTION:
9403 case IDENTIFIER:
9404 case SUPER:
9405 case SELF:
9406 case SELF_ALIAS:
9407 case CRATE:
9408 case DOLLAR_SIGN: {
9409 // path, so trait type
9410
9411 // parse type path to finish parsing trait bound
9412 AST::TypePath path = parse_type_path ();
9413
9414 t = lexer.peek_token ();
9415 if (t->get_id () != PLUS)
9416 {
9417 // must be one-bound trait type
9418 // create trait bound value object
9419 AST::TraitBound bound (std::move (path), for_locus, false, false,
9420 std::move (for_lifetimes));
9421
9422 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
9423 new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
9424 }
9425
9426 /* more than one bound trait type (or at least parsed as it - could be
9427 * trailing '+') create trait bound pointer and bounds */
9428 std::unique_ptr<AST::TraitBound> initial_bound (
9429 new AST::TraitBound (std::move (path), for_locus, false, false,
9430 std::move (for_lifetimes)));
9431 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9432 bounds.push_back (std::move (initial_bound));
9433
9434 while (t->get_id () == PLUS)
9435 {
9436 lexer.skip_token ();
9437
9438 // parse type param bound if it exists
9439 std::unique_ptr<AST::TypeParamBound> bound
9440 = parse_type_param_bound ();
9441 if (bound == nullptr)
9442 {
9443 // not an error - e.g. trailing plus
9444 return nullptr;
9445 }
9446 bounds.push_back (std::move (bound));
9447
9448 t = lexer.peek_token ();
9449 }
9450
9451 return std::unique_ptr<AST::TraitObjectType> (
9452 new AST::TraitObjectType (std::move (bounds), for_locus, false));
9453 }
9454 default:
9455 // error
9456 add_error (Error (t->get_locus (),
9457 "unrecognised token %qs in bare function type or trait "
9458 "object type or trait object type one bound",
9459 t->get_token_description ()));
9460
9461 return nullptr;
9462 }
9463}
9464
9465// Parses a maybe named param used in bare function types.
9466template <typename ManagedTokenSource>
9467AST::MaybeNamedParam
9468Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
9469{
9470 /* Basically guess that param is named if first token is identifier or
9471 * underscore and second token is semicolon. This should probably have no
9472 * exceptions. rustc uses backtracking to parse these, but at the time of
9473 * writing gccrs has no backtracking capabilities. */
9474 const_TokenPtr current = lexer.peek_token ();
9475 const_TokenPtr next = lexer.peek_token (1);
9476
9477 Identifier name;
9478 AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
9479
9480 if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
9481 {
9482 // named param
1c3a8fbb 9483 name = {current};
32c8fb0e
JP
9484 kind = AST::MaybeNamedParam::IDENTIFIER;
9485 lexer.skip_token (1);
9486 }
9487 else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
9488 {
9489 // wildcard param
f1c7ce7e 9490 name = {Values::Keywords::UNDERSCORE, current->get_locus ()};
32c8fb0e
JP
9491 kind = AST::MaybeNamedParam::WILDCARD;
9492 lexer.skip_token (1);
9493 }
9494
9495 // parse type (required)
9496 std::unique_ptr<AST::Type> type = parse_type ();
9497 if (type == nullptr)
9498 {
9499 Error error (lexer.peek_token ()->get_locus (),
9500 "failed to parse type in maybe named param");
9501 add_error (std::move (error));
9502
9503 return AST::MaybeNamedParam::create_error ();
9504 }
9505
9506 return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
9507 std::move (outer_attrs), current->get_locus ());
9508}
9509
9510/* Parses a bare function type (with the given for lifetimes for convenience -
9511 * does not parse them itself). */
9512template <typename ManagedTokenSource>
9513std::unique_ptr<AST::BareFunctionType>
9514Parser<ManagedTokenSource>::parse_bare_function_type (
9515 std::vector<AST::LifetimeParam> for_lifetimes)
9516{
9517 // TODO: pass in for lifetime location as param
80c68893 9518 location_t best_try_locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
9519
9520 AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
9521
7f631967 9522 if (!skip_token (FN_KW))
32c8fb0e
JP
9523 return nullptr;
9524
9525 if (!skip_token (LEFT_PAREN))
9526 return nullptr;
9527
9528 // parse function params, if they exist
9529 std::vector<AST::MaybeNamedParam> params;
9530 bool is_variadic = false;
9531 AST::AttrVec variadic_attrs;
9532
9533 const_TokenPtr t = lexer.peek_token ();
9534 while (t->get_id () != RIGHT_PAREN)
9535 {
9536 AST::AttrVec temp_attrs = parse_outer_attributes ();
9537
9538 if (lexer.peek_token ()->get_id () == ELLIPSIS)
9539 {
9540 lexer.skip_token ();
9541 is_variadic = true;
9542 variadic_attrs = std::move (temp_attrs);
9543
9544 t = lexer.peek_token ();
9545
9546 if (t->get_id () != RIGHT_PAREN)
9547 {
9548 Error error (t->get_locus (),
9549 "expected right parentheses after variadic in maybe "
9550 "named function "
9551 "parameters, found %qs",
9552 t->get_token_description ());
9553 add_error (std::move (error));
9554
9555 return nullptr;
9556 }
9557
9558 break;
9559 }
9560
9561 AST::MaybeNamedParam param
9562 = parse_maybe_named_param (std::move (temp_attrs));
9563 if (param.is_error ())
9564 {
9565 Error error (
9566 lexer.peek_token ()->get_locus (),
9567 "failed to parse maybe named param in bare function type");
9568 add_error (std::move (error));
9569
9570 return nullptr;
9571 }
9572 params.push_back (std::move (param));
9573
9574 if (lexer.peek_token ()->get_id () != COMMA)
9575 break;
9576
9577 lexer.skip_token ();
9578 t = lexer.peek_token ();
9579 }
9580
9581 if (!skip_token (RIGHT_PAREN))
9582 return nullptr;
9583
9584 // bare function return type, if exists
9585 std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
9586 if (lexer.peek_token ()->get_id () == RETURN_TYPE)
9587 {
9588 lexer.skip_token ();
9589
9590 // parse required TypeNoBounds
9591 return_type = parse_type_no_bounds ();
9592 if (return_type == nullptr)
9593 {
9594 Error error (lexer.peek_token ()->get_locus (),
9595 "failed to parse return type (type no bounds) in bare "
9596 "function type");
9597 add_error (std::move (error));
9598
9599 return nullptr;
9600 }
9601 }
9602
9603 return std::unique_ptr<AST::BareFunctionType> (
9604 new AST::BareFunctionType (std::move (for_lifetimes),
9605 std::move (qualifiers), std::move (params),
9606 is_variadic, std::move (variadic_attrs),
9607 std::move (return_type), best_try_locus));
9608}
9609
32c8fb0e
JP
9610template <typename ManagedTokenSource>
9611std::unique_ptr<AST::ReferenceType>
d991a3f1 9612Parser<ManagedTokenSource>::parse_reference_type_inner (location_t locus)
32c8fb0e 9613{
32c8fb0e 9614 // parse optional lifetime
50f30592 9615 AST::Lifetime lifetime = AST::Lifetime::elided ();
32c8fb0e
JP
9616 if (lexer.peek_token ()->get_id () == LIFETIME)
9617 {
827ceac9
PEP
9618 auto parsed_lifetime = parse_lifetime (true);
9619 if (parsed_lifetime)
9620 {
9621 lifetime = parsed_lifetime.value ();
9622 }
9623 else
32c8fb0e
JP
9624 {
9625 Error error (lexer.peek_token ()->get_locus (),
9626 "failed to parse lifetime in reference type");
9627 add_error (std::move (error));
9628
9629 return nullptr;
9630 }
9631 }
9632
9633 bool is_mut = false;
9634 if (lexer.peek_token ()->get_id () == MUT)
9635 {
9636 lexer.skip_token ();
9637 is_mut = true;
9638 }
9639
9640 // parse type no bounds, which is required
9641 std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
9642 if (type == nullptr)
9643 {
9644 Error error (lexer.peek_token ()->get_locus (),
9645 "failed to parse referenced type in reference type");
9646 add_error (std::move (error));
9647
9648 return nullptr;
9649 }
9650
9651 return std::unique_ptr<AST::ReferenceType> (
9652 new AST::ReferenceType (is_mut, std::move (type), locus,
9653 std::move (lifetime)));
9654}
9655
9cbd2706
AC
9656// Parses a reference type (mutable or immutable, with given lifetime).
9657template <typename ManagedTokenSource>
9658std::unique_ptr<AST::ReferenceType>
9659Parser<ManagedTokenSource>::parse_reference_type ()
9660{
9661 auto t = lexer.peek_token ();
9662 auto locus = t->get_locus ();
9663
9664 switch (t->get_id ())
9665 {
9666 case AMP:
9667 skip_token (AMP);
9668 return parse_reference_type_inner (locus);
9669 case LOGICAL_AND:
9670 skip_token (LOGICAL_AND);
9671 return std::unique_ptr<AST::ReferenceType> (
9672 new AST::ReferenceType (false, parse_reference_type_inner (locus),
9673 locus));
9674 default:
93866b6a 9675 rust_unreachable ();
9cbd2706
AC
9676 }
9677}
9678
32c8fb0e
JP
9679// Parses a raw (unsafe) pointer type.
9680template <typename ManagedTokenSource>
9681std::unique_ptr<AST::RawPointerType>
9682Parser<ManagedTokenSource>::parse_raw_pointer_type ()
9683{
d991a3f1 9684 location_t locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
9685 skip_token (ASTERISK);
9686
9687 AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
9688
9689 // branch on next token for pointer kind info
9690 const_TokenPtr t = lexer.peek_token ();
9691 switch (t->get_id ())
9692 {
9693 case MUT:
9694 kind = AST::RawPointerType::MUT;
9695 lexer.skip_token ();
9696 break;
9697 case CONST:
9698 kind = AST::RawPointerType::CONST;
9699 lexer.skip_token ();
9700 break;
9701 default:
9702 add_error (Error (t->get_locus (),
9703 "unrecognised token %qs in raw pointer type",
9704 t->get_token_description ()));
9705
9706 return nullptr;
9707 }
9708
9709 // parse type no bounds (required)
9710 std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
9711 if (type == nullptr)
9712 {
9713 Error error (lexer.peek_token ()->get_locus (),
9714 "failed to parse pointed type of raw pointer type");
9715 add_error (std::move (error));
9716
9717 return nullptr;
9718 }
9719
9720 return std::unique_ptr<AST::RawPointerType> (
9721 new AST::RawPointerType (kind, std::move (type), locus));
9722}
9723
9724/* Parses a slice or array type, depending on following arguments (as
9725 * lookahead is not possible). */
9726template <typename ManagedTokenSource>
9727std::unique_ptr<AST::TypeNoBounds>
9728Parser<ManagedTokenSource>::parse_slice_or_array_type ()
9729{
d991a3f1 9730 location_t locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
9731 skip_token (LEFT_SQUARE);
9732
9733 // parse inner type (required)
9734 std::unique_ptr<AST::Type> inner_type = parse_type ();
9735 if (inner_type == nullptr)
9736 {
9737 Error error (lexer.peek_token ()->get_locus (),
9738 "failed to parse inner type in slice or array type");
9739 add_error (std::move (error));
9740
9741 return nullptr;
9742 }
9743
9744 // branch on next token
9745 const_TokenPtr t = lexer.peek_token ();
9746 switch (t->get_id ())
9747 {
9748 case RIGHT_SQUARE:
9749 // slice type
9750 lexer.skip_token ();
9751
9752 return std::unique_ptr<AST::SliceType> (
9753 new AST::SliceType (std::move (inner_type), locus));
9754 case SEMICOLON: {
9755 // array type
9756 lexer.skip_token ();
9757
9758 // parse required array size expression
9759 std::unique_ptr<AST::Expr> size = parse_expr ();
9760 if (size == nullptr)
9761 {
9762 Error error (lexer.peek_token ()->get_locus (),
9763 "failed to parse size expression in array type");
9764 add_error (std::move (error));
9765
9766 return nullptr;
9767 }
9768
9769 if (!skip_token (RIGHT_SQUARE))
9770 {
9771 return nullptr;
9772 }
9773
9774 return std::unique_ptr<AST::ArrayType> (
9775 new AST::ArrayType (std::move (inner_type), std::move (size), locus));
9776 }
9777 default:
9778 // error
9779 add_error (
9780 Error (t->get_locus (),
9781 "unrecognised token %qs in slice or array type after inner type",
9782 t->get_token_description ()));
9783
9784 return nullptr;
9785 }
9786}
9787
9788// Parses a type, taking into account type boundary disambiguation.
9789template <typename ManagedTokenSource>
9790std::unique_ptr<AST::TypeNoBounds>
9791Parser<ManagedTokenSource>::parse_type_no_bounds ()
9792{
9793 const_TokenPtr t = lexer.peek_token ();
9794 switch (t->get_id ())
9795 {
9796 case EXCLAM:
9797 // never type - can't be macro as no path beforehand
9798 lexer.skip_token ();
9799 return std::unique_ptr<AST::NeverType> (
9800 new AST::NeverType (t->get_locus ()));
9801 case LEFT_SQUARE:
9802 // slice type or array type - requires further disambiguation
9803 return parse_slice_or_array_type ();
2a094010 9804 case LEFT_SHIFT:
32c8fb0e
JP
9805 case LEFT_ANGLE: {
9806 // qualified path in type
9807 AST::QualifiedPathInType path = parse_qualified_path_in_type ();
9808 if (path.is_error ())
9809 {
9810 Error error (t->get_locus (),
9811 "failed to parse qualified path in type");
9812 add_error (std::move (error));
9813
9814 return nullptr;
9815 }
9816 return std::unique_ptr<AST::QualifiedPathInType> (
9817 new AST::QualifiedPathInType (std::move (path)));
9818 }
9819 case UNDERSCORE:
9820 // inferred type
9821 lexer.skip_token ();
9822 return std::unique_ptr<AST::InferredType> (
9823 new AST::InferredType (t->get_locus ()));
9824 case ASTERISK:
9825 // raw pointer type
9826 return parse_raw_pointer_type ();
9cbd2706
AC
9827 case AMP: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
9828 case LOGICAL_AND:
32c8fb0e
JP
9829 // reference type
9830 return parse_reference_type ();
9831 case LIFETIME:
9832 /* probably a lifetime bound, so probably type param bounds in
9833 * TraitObjectType. this is not allowed, but detection here for error
9834 * message */
9835 add_error (Error (t->get_locus (),
9836 "lifetime bounds (i.e. in type param bounds, in "
9837 "TraitObjectType) are not allowed as TypeNoBounds"));
9838
9839 return nullptr;
9840 case IDENTIFIER:
9841 case SUPER:
9842 case SELF:
9843 case SELF_ALIAS:
9844 case CRATE:
9845 case DOLLAR_SIGN:
9846 case SCOPE_RESOLUTION: {
9847 // macro invocation or type path - requires further disambiguation.
9848 /* for parsing path component of each rule, perhaps parse it as a
9849 * typepath and attempt conversion to simplepath if a trailing '!' is
9850 * found */
9851 /* Type path also includes TraitObjectTypeOneBound BUT if it starts
9852 * with it, it is exactly the same as a TypePath syntactically, so
9853 * this is a syntactical ambiguity. As such, the parser will parse it
9854 * as a TypePath. This, however, does not prevent TraitObjectType from
9855 * starting with a typepath. */
9856
9857 // parse path as type path
9858 AST::TypePath path = parse_type_path ();
9859 if (path.is_error ())
9860 {
9861 Error error (
9862 t->get_locus (),
9863 "failed to parse path as first component of type no bounds");
9864 add_error (std::move (error));
9865
9866 return nullptr;
9867 }
d991a3f1 9868 location_t locus = path.get_locus ();
32c8fb0e
JP
9869
9870 // branch on next token
9871 t = lexer.peek_token ();
9872 switch (t->get_id ())
9873 {
9874 case EXCLAM: {
9875 // macro invocation
9876 // convert to simple path
9877 AST::SimplePath macro_path = path.as_simple_path ();
9878 if (macro_path.is_empty ())
9879 {
9880 Error error (t->get_locus (),
9881 "failed to parse simple path in macro "
9882 "invocation (for type)");
9883 add_error (std::move (error));
9884
9885 return nullptr;
9886 }
9887
9888 lexer.skip_token ();
9889
9890 AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
9891
51b607c2
AC
9892 return AST::MacroInvocation::Regular (
9893 AST::MacroInvocData (std::move (macro_path),
9894 std::move (tok_tree)),
9895 {}, locus);
32c8fb0e
JP
9896 }
9897 default:
9898 // assume that this is a type path and not an error
9899 return std::unique_ptr<AST::TypePath> (
9900 new AST::TypePath (std::move (path)));
9901 }
9902 }
9903 case LEFT_PAREN:
9904 /* tuple type or parenthesised type - requires further disambiguation
9905 * (the usual). ok apparently can be a parenthesised TraitBound too, so
9906 * could be TraitObjectTypeOneBound */
9907 return parse_paren_prefixed_type_no_bounds ();
9908 case FOR:
9909 case ASYNC:
9910 case CONST:
9911 case UNSAFE:
7f631967
PEP
9912 case EXTERN_KW:
9913 case FN_KW:
32c8fb0e
JP
9914 // bare function type (with no for lifetimes)
9915 return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
9916 case IMPL:
9917 lexer.skip_token ();
9918 if (lexer.peek_token ()->get_id () == LIFETIME)
9919 {
9920 /* cannot be one bound because lifetime prevents it from being
9921 * traitbound not allowed as type no bounds, only here for error
9922 * message */
9923 Error error (
9924 lexer.peek_token ()->get_locus (),
9925 "lifetime (probably lifetime bound, in type param "
9926 "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
9927 add_error (std::move (error));
9928
9929 return nullptr;
9930 }
9931 else
9932 {
9933 // should be trait bound, so parse trait bound
9934 std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
9935 if (initial_bound == nullptr)
9936 {
9937 Error error (lexer.peek_token ()->get_locus (),
9938 "failed to parse ImplTraitTypeOneBound bound");
9939 add_error (std::move (error));
9940
9941 return nullptr;
9942 }
9943
d991a3f1 9944 location_t locus = t->get_locus ();
32c8fb0e
JP
9945
9946 // ensure not a trait with multiple bounds
9947 t = lexer.peek_token ();
9948 if (t->get_id () == PLUS)
9949 {
9950 Error error (t->get_locus (),
9951 "plus after trait bound means an ImplTraitType, "
9952 "which is not allowed as a TypeNoBounds");
9953 add_error (std::move (error));
9954
9955 return nullptr;
9956 }
9957
9958 // convert trait bound to value object
9959 AST::TraitBound value_bound (*initial_bound);
9960
9961 return std::unique_ptr<AST::ImplTraitTypeOneBound> (
9962 new AST::ImplTraitTypeOneBound (std::move (value_bound), locus));
9963 }
9964 case DYN:
9965 case QUESTION_MARK: {
9966 // either TraitObjectTypeOneBound
9967 bool has_dyn = false;
9968 if (t->get_id () == DYN)
9969 {
9970 lexer.skip_token ();
9971 has_dyn = true;
9972 }
9973
9974 if (lexer.peek_token ()->get_id () == LIFETIME)
9975 {
9976 /* means that cannot be TraitObjectTypeOneBound - so here for
9977 * error message */
9978 Error error (lexer.peek_token ()->get_locus (),
9979 "lifetime as bound in TraitObjectTypeOneBound "
9980 "is not allowed, so cannot be TypeNoBounds");
9981 add_error (std::move (error));
9982
9983 return nullptr;
9984 }
9985
9986 // should be trait bound, so parse trait bound
9987 std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
9988 if (initial_bound == nullptr)
9989 {
9990 Error error (
9991 lexer.peek_token ()->get_locus (),
9992 "failed to parse TraitObjectTypeOneBound initial bound");
9993 add_error (std::move (error));
9994
9995 return nullptr;
9996 }
9997
d991a3f1 9998 location_t locus = t->get_locus ();
32c8fb0e
JP
9999
10000 // detect error with plus as next token
10001 t = lexer.peek_token ();
10002 if (t->get_id () == PLUS)
10003 {
10004 Error error (t->get_locus (),
10005 "plus after trait bound means a TraitObjectType, "
10006 "which is not allowed as a TypeNoBounds");
10007 add_error (std::move (error));
10008
10009 return nullptr;
10010 }
10011
10012 // convert trait bound to value object
10013 AST::TraitBound value_bound (*initial_bound);
10014
10015 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
10016 new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
10017 has_dyn));
10018 }
10019 default:
10020 add_error (Error (t->get_locus (),
10021 "unrecognised token %qs in type no bounds",
10022 t->get_token_description ()));
10023
10024 return nullptr;
10025 }
10026}
10027
10028// Parses a type no bounds beginning with '('.
10029template <typename ManagedTokenSource>
10030std::unique_ptr<AST::TypeNoBounds>
10031Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
10032{
10033 /* NOTE: this could probably be parsed without the HACK solution of
10034 * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
10035
10036 /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
10037 * considered a trait bound, not a parenthesised type, so that it can still
10038 * be used in type param bounds. */
10039
80c68893 10040 location_t left_paren_locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
10041
10042 // skip left delim
10043 lexer.skip_token ();
10044 /* while next token isn't close delim, parse comma-separated types, saving
10045 * whether trailing comma happens */
10046 const_TokenPtr t = lexer.peek_token ();
10047 bool trailing_comma = true;
10048 std::vector<std::unique_ptr<AST::Type>> types;
10049
10050 while (t->get_id () != RIGHT_PAREN)
10051 {
10052 std::unique_ptr<AST::Type> type = parse_type ();
10053 if (type == nullptr)
10054 {
10055 Error error (t->get_locus (),
10056 "failed to parse type inside parentheses (probably "
10057 "tuple or parenthesised)");
10058 add_error (std::move (error));
10059
10060 return nullptr;
10061 }
10062 types.push_back (std::move (type));
10063
10064 t = lexer.peek_token ();
10065 if (t->get_id () != COMMA)
10066 {
10067 trailing_comma = false;
10068 break;
10069 }
10070 lexer.skip_token ();
10071
10072 t = lexer.peek_token ();
10073 }
10074
10075 if (!skip_token (RIGHT_PAREN))
10076 {
10077 return nullptr;
10078 }
10079
10080 // if only one type and no trailing comma, then not a tuple type
10081 if (types.size () == 1 && !trailing_comma)
10082 {
10083 // must be a TraitObjectType (with more than one bound)
10084 if (lexer.peek_token ()->get_id () == PLUS)
10085 {
10086 // error - this is not allowed for type no bounds
10087 Error error (lexer.peek_token ()->get_locus (),
10088 "plus (implying TraitObjectType as type param "
10089 "bounds) is not allowed in type no bounds");
10090 add_error (std::move (error));
10091
10092 return nullptr;
10093 }
10094 else
10095 {
10096 // release vector pointer
10097 std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
10098 /* HACK: attempt to convert to trait bound. if fails, parenthesised
10099 * type */
10100 std::unique_ptr<AST::TraitBound> converted_bound (
10101 released_ptr->to_trait_bound (true));
10102 if (converted_bound == nullptr)
10103 {
10104 // parenthesised type
10105 return std::unique_ptr<AST::ParenthesisedType> (
10106 new AST::ParenthesisedType (std::move (released_ptr),
10107 left_paren_locus));
10108 }
10109 else
10110 {
10111 // trait object type (one bound)
10112
10113 // get value semantics trait bound
10114 AST::TraitBound value_bound (*converted_bound);
10115
10116 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
10117 new AST::TraitObjectTypeOneBound (value_bound,
10118 left_paren_locus));
10119 }
10120 }
10121 }
10122 else
10123 {
10124 return std::unique_ptr<AST::TupleType> (
10125 new AST::TupleType (std::move (types), left_paren_locus));
10126 }
10127 /* TODO: ensure that this ensures that dynamic dispatch for traits is not
10128 * lost somehow */
10129}
10130
10131/* Parses a literal pattern or range pattern. Assumes that literals passed in
10132 * are valid range pattern bounds. Do not pass in paths in expressions, for
10133 * instance. */
10134template <typename ManagedTokenSource>
10135std::unique_ptr<AST::Pattern>
10136Parser<ManagedTokenSource>::parse_literal_or_range_pattern ()
10137{
10138 const_TokenPtr range_lower = lexer.peek_token ();
10139 AST::Literal::LitType type = AST::Literal::STRING;
10140 bool has_minus = false;
10141
10142 // get lit type
10143 switch (range_lower->get_id ())
10144 {
10145 case CHAR_LITERAL:
10146 type = AST::Literal::CHAR;
10147 lexer.skip_token ();
10148 break;
10149 case BYTE_CHAR_LITERAL:
10150 type = AST::Literal::BYTE;
10151 lexer.skip_token ();
10152 break;
10153 case INT_LITERAL:
10154 type = AST::Literal::INT;
10155 lexer.skip_token ();
10156 break;
10157 case FLOAT_LITERAL:
10158 type = AST::Literal::FLOAT;
10159 lexer.skip_token ();
10160 break;
10161 case MINUS:
10162 // branch on next token
10163 range_lower = lexer.peek_token (1);
10164 switch (range_lower->get_id ())
10165 {
10166 case INT_LITERAL:
10167 type = AST::Literal::INT;
10168 has_minus = true;
10169 lexer.skip_token (1);
10170 break;
10171 case FLOAT_LITERAL:
10172 type = AST::Literal::FLOAT;
10173 has_minus = true;
10174 lexer.skip_token (1);
10175 break;
10176 default:
10177 add_error (Error (range_lower->get_locus (),
10178 "token type %qs cannot be parsed as range pattern "
10179 "bound or literal after minus symbol",
10180 range_lower->get_token_description ()));
10181
10182 return nullptr;
10183 }
10184 break;
10185 default:
10186 add_error (
10187 Error (range_lower->get_locus (),
10188 "token type %qs cannot be parsed as range pattern bound",
10189 range_lower->get_token_description ()));
10190
10191 return nullptr;
10192 }
10193
10194 const_TokenPtr next = lexer.peek_token ();
cc7ec392
PEP
10195 if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS
10196 || next->get_id () == DOT_DOT)
32c8fb0e 10197 {
cc7ec392 10198 AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
32c8fb0e
JP
10199 // range pattern
10200 lexer.skip_token ();
10201 std::unique_ptr<AST::RangePatternBound> lower (
10202 new AST::RangePatternBoundLiteral (
10203 AST::Literal (range_lower->get_str (), type,
10204 PrimitiveCoreType::CORETYPE_UNKNOWN),
10205 range_lower->get_locus (), has_minus));
10206
10207 std::unique_ptr<AST::RangePatternBound> upper
10208 = parse_range_pattern_bound ();
10209 if (upper == nullptr)
10210 {
10211 Error error (next->get_locus (),
10212 "failed to parse range pattern bound in range pattern");
10213 add_error (std::move (error));
10214
10215 return nullptr;
10216 }
10217
10218 return std::unique_ptr<AST::RangePattern> (
cc7ec392 10219 new AST::RangePattern (std::move (lower), std::move (upper), kind,
32c8fb0e
JP
10220 range_lower->get_locus ()));
10221 }
10222 else
10223 {
10224 // literal pattern
10225 return std::unique_ptr<AST::LiteralPattern> (
10226 new AST::LiteralPattern (range_lower->get_str (), type,
e6c44bae
PEP
10227 range_lower->get_locus (),
10228 range_lower->get_type_hint ()));
32c8fb0e
JP
10229 }
10230}
10231
10232// Parses a range pattern bound (value only).
10233template <typename ManagedTokenSource>
10234std::unique_ptr<AST::RangePatternBound>
10235Parser<ManagedTokenSource>::parse_range_pattern_bound ()
10236{
10237 const_TokenPtr range_lower = lexer.peek_token ();
80c68893 10238 location_t range_lower_locus = range_lower->get_locus ();
32c8fb0e
JP
10239
10240 // get lit type
10241 switch (range_lower->get_id ())
10242 {
10243 case CHAR_LITERAL:
10244 lexer.skip_token ();
10245 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10246 new AST::RangePatternBoundLiteral (
10247 AST::Literal (range_lower->get_str (), AST::Literal::CHAR,
10248 range_lower->get_type_hint ()),
10249 range_lower_locus));
10250 case BYTE_CHAR_LITERAL:
10251 lexer.skip_token ();
10252 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10253 new AST::RangePatternBoundLiteral (
10254 AST::Literal (range_lower->get_str (), AST::Literal::BYTE,
10255 range_lower->get_type_hint ()),
10256 range_lower_locus));
10257 case INT_LITERAL:
10258 lexer.skip_token ();
10259 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10260 new AST::RangePatternBoundLiteral (
10261 AST::Literal (range_lower->get_str (), AST::Literal::INT,
10262 range_lower->get_type_hint ()),
10263 range_lower_locus));
10264 case FLOAT_LITERAL:
10265 lexer.skip_token ();
10266 rust_debug ("warning: used deprecated float range pattern bound");
10267 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10268 new AST::RangePatternBoundLiteral (
10269 AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
10270 range_lower->get_type_hint ()),
10271 range_lower_locus));
10272 case MINUS:
10273 // branch on next token
10274 range_lower = lexer.peek_token (1);
10275 switch (range_lower->get_id ())
10276 {
10277 case INT_LITERAL:
10278 lexer.skip_token (1);
10279 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10280 new AST::RangePatternBoundLiteral (
10281 AST::Literal (range_lower->get_str (), AST::Literal::INT,
10282 range_lower->get_type_hint ()),
10283 range_lower_locus, true));
10284 case FLOAT_LITERAL:
10285 lexer.skip_token (1);
10286 rust_debug ("warning: used deprecated float range pattern bound");
10287 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10288 new AST::RangePatternBoundLiteral (
10289 AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
10290 range_lower->get_type_hint ()),
10291 range_lower_locus, true));
10292 default:
10293 add_error (Error (range_lower->get_locus (),
10294 "token type %qs cannot be parsed as range pattern "
10295 "bound after minus symbol",
10296 range_lower->get_token_description ()));
10297
10298 return nullptr;
10299 }
10300 case IDENTIFIER:
10301 case SUPER:
10302 case SELF:
10303 case SELF_ALIAS:
10304 case CRATE:
10305 case SCOPE_RESOLUTION:
10306 case DOLLAR_SIGN: {
10307 // path in expression
10308 AST::PathInExpression path = parse_path_in_expression ();
10309 if (path.is_error ())
10310 {
10311 Error error (
10312 range_lower->get_locus (),
10313 "failed to parse path in expression range pattern bound");
10314 add_error (std::move (error));
10315
10316 return nullptr;
10317 }
10318 return std::unique_ptr<AST::RangePatternBoundPath> (
10319 new AST::RangePatternBoundPath (std::move (path)));
10320 }
2a094010 10321 case LEFT_SHIFT:
32c8fb0e
JP
10322 case LEFT_ANGLE: {
10323 // qualified path in expression
10324 AST::QualifiedPathInExpression path
10325 = parse_qualified_path_in_expression ();
10326 if (path.is_error ())
10327 {
10328 Error error (range_lower->get_locus (),
10329 "failed to parse qualified path in expression range "
10330 "pattern bound");
10331 add_error (std::move (error));
10332
10333 return nullptr;
10334 }
10335 return std::unique_ptr<AST::RangePatternBoundQualPath> (
10336 new AST::RangePatternBoundQualPath (std::move (path)));
10337 }
10338 default:
10339 add_error (
10340 Error (range_lower->get_locus (),
10341 "token type %qs cannot be parsed as range pattern bound",
10342 range_lower->get_token_description ()));
10343
10344 return nullptr;
10345 }
10346}
10347
32c8fb0e
JP
10348template <typename ManagedTokenSource>
10349std::unique_ptr<AST::Pattern>
10350Parser<ManagedTokenSource>::parse_pattern ()
4bd09ce0 10351{
80c68893 10352 location_t start_locus = lexer.peek_token ()->get_locus ();
4bd09ce0
OA
10353
10354 /* skip optional starting pipe */
10355 maybe_skip_token (PIPE);
10356
10357 auto first = parse_pattern_no_alt ();
10358
10359 if (lexer.peek_token ()->get_id () != PIPE)
10360 /* no alternates */
10361 return first;
10362
10363 std::vector<std::unique_ptr<AST::Pattern>> alts;
10364 alts.push_back (std::move (first));
10365
10366 do
10367 {
10368 lexer.skip_token ();
10369 alts.push_back (parse_pattern_no_alt ());
293ac1ba 10370 }
10371
10372 while (lexer.peek_token ()->get_id () == PIPE);
4bd09ce0
OA
10373
10374 /* alternates */
10375 return std::unique_ptr<AST::Pattern> (
10376 new AST::AltPattern (std::move (alts), start_locus));
10377}
10378
10379// Parses a pattern without alternates ('|')
10380// (will further disambiguate any pattern).
10381template <typename ManagedTokenSource>
10382std::unique_ptr<AST::Pattern>
10383Parser<ManagedTokenSource>::parse_pattern_no_alt ()
32c8fb0e
JP
10384{
10385 const_TokenPtr t = lexer.peek_token ();
10386 switch (t->get_id ())
10387 {
10388 case TRUE_LITERAL:
10389 lexer.skip_token ();
10390 return std::unique_ptr<AST::LiteralPattern> (
f1c7ce7e
PEP
10391 new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL,
10392 AST::Literal::BOOL, t->get_locus (),
e6c44bae 10393 t->get_type_hint ()));
32c8fb0e
JP
10394 case FALSE_LITERAL:
10395 lexer.skip_token ();
10396 return std::unique_ptr<AST::LiteralPattern> (
f1c7ce7e
PEP
10397 new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL,
10398 AST::Literal::BOOL, t->get_locus (),
e6c44bae 10399 t->get_type_hint ()));
32c8fb0e
JP
10400 case CHAR_LITERAL:
10401 case BYTE_CHAR_LITERAL:
10402 case INT_LITERAL:
10403 case FLOAT_LITERAL:
10404 return parse_literal_or_range_pattern ();
10405 case STRING_LITERAL:
10406 lexer.skip_token ();
10407 return std::unique_ptr<AST::LiteralPattern> (
10408 new AST::LiteralPattern (t->get_str (), AST::Literal::STRING,
e6c44bae 10409 t->get_locus (), t->get_type_hint ()));
32c8fb0e
JP
10410 case BYTE_STRING_LITERAL:
10411 lexer.skip_token ();
10412 return std::unique_ptr<AST::LiteralPattern> (
10413 new AST::LiteralPattern (t->get_str (), AST::Literal::BYTE_STRING,
e6c44bae 10414 t->get_locus (), t->get_type_hint ()));
908a4f88 10415 case RAW_STRING_LITERAL:
10416 lexer.skip_token ();
10417 return std::unique_ptr<AST::LiteralPattern> (
10418 new AST::LiteralPattern (t->get_str (), AST::Literal::RAW_STRING,
10419 t->get_locus (), t->get_type_hint ()));
32c8fb0e
JP
10420 // raw string and raw byte string literals too if they are readded to
10421 // lexer
10422 case MINUS:
10423 if (lexer.peek_token (1)->get_id () == INT_LITERAL)
10424 {
10425 return parse_literal_or_range_pattern ();
10426 }
10427 else if (lexer.peek_token (1)->get_id () == FLOAT_LITERAL)
10428 {
10429 return parse_literal_or_range_pattern ();
10430 }
10431 else
10432 {
10433 Error error (t->get_locus (), "unexpected token %<-%> in pattern - "
10434 "did you forget an integer literal");
10435 add_error (std::move (error));
10436
10437 return nullptr;
10438 }
10439 case UNDERSCORE:
10440 lexer.skip_token ();
10441 return std::unique_ptr<AST::WildcardPattern> (
10442 new AST::WildcardPattern (t->get_locus ()));
c9644897
PEP
10443 case DOT_DOT:
10444 lexer.skip_token ();
10445 return std::unique_ptr<AST::RestPattern> (
10446 new AST::RestPattern (t->get_locus ()));
32c8fb0e
JP
10447 case REF:
10448 case MUT:
10449 return parse_identifier_pattern ();
10450 case IDENTIFIER:
10451 /* if identifier with no scope resolution afterwards, identifier
10452 * pattern. if scope resolution afterwards, path pattern (or range
10453 * pattern or struct pattern or tuple struct pattern) or macro
10454 * invocation */
10455 return parse_ident_leading_pattern ();
10456 case AMP:
10457 case LOGICAL_AND:
10458 // reference pattern
10459 return parse_reference_pattern ();
10460 case LEFT_PAREN:
10461 // tuple pattern or grouped pattern
10462 return parse_grouped_or_tuple_pattern ();
10463 case LEFT_SQUARE:
10464 // slice pattern
10465 return parse_slice_pattern ();
2a094010 10466 case LEFT_SHIFT:
32c8fb0e
JP
10467 case LEFT_ANGLE: {
10468 // qualified path in expression or qualified range pattern bound
10469 AST::QualifiedPathInExpression path
10470 = parse_qualified_path_in_expression ();
10471
10472 if (lexer.peek_token ()->get_id () == DOT_DOT_EQ
cc7ec392
PEP
10473 || lexer.peek_token ()->get_id () == ELLIPSIS
10474 || lexer.peek_token ()->get_id () == DOT_DOT)
32c8fb0e
JP
10475 {
10476 // qualified range pattern bound, so parse rest of range pattern
cc7ec392
PEP
10477 AST::RangeKind kind
10478 = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
32c8fb0e
JP
10479 lexer.skip_token ();
10480
10481 std::unique_ptr<AST::RangePatternBoundQualPath> lower_bound (
10482 new AST::RangePatternBoundQualPath (std::move (path)));
10483 std::unique_ptr<AST::RangePatternBound> upper_bound
10484 = parse_range_pattern_bound ();
10485
10486 return std::unique_ptr<AST::RangePattern> (
10487 new AST::RangePattern (std::move (lower_bound),
cc7ec392
PEP
10488 std::move (upper_bound), kind,
10489 t->get_locus ()));
32c8fb0e
JP
10490 }
10491 else
10492 {
10493 // just qualified path in expression
10494 return std::unique_ptr<AST::QualifiedPathInExpression> (
10495 new AST::QualifiedPathInExpression (std::move (path)));
10496 }
10497 }
10498 case SUPER:
10499 case SELF:
10500 case SELF_ALIAS:
10501 case CRATE:
10502 case SCOPE_RESOLUTION:
10503 case DOLLAR_SIGN: {
10504 // path in expression or range pattern bound
10505 AST::PathInExpression path = parse_path_in_expression ();
10506
10507 const_TokenPtr next = lexer.peek_token ();
10508 switch (next->get_id ())
10509 {
10510 case DOT_DOT_EQ:
cc7ec392 10511 case DOT_DOT:
32c8fb0e
JP
10512 case ELLIPSIS: {
10513 // qualified range pattern bound, so parse rest of range pattern
cc7ec392 10514 AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
32c8fb0e
JP
10515 lexer.skip_token ();
10516
10517 std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
10518 new AST::RangePatternBoundPath (std::move (path)));
10519 std::unique_ptr<AST::RangePatternBound> upper_bound
10520 = parse_range_pattern_bound ();
10521
e5f3ad0f
OA
10522 return std::unique_ptr<AST::RangePattern> (
10523 new AST::RangePattern (std::move (lower_bound),
cc7ec392 10524 std::move (upper_bound), kind,
ab89ab37 10525 next->get_locus ()));
32c8fb0e
JP
10526 }
10527 case EXCLAM:
10528 return parse_macro_invocation_partial (std::move (path),
10529 AST::AttrVec ());
10530 case LEFT_PAREN: {
10531 // tuple struct
10532 lexer.skip_token ();
10533
32c8fb0e
JP
10534 // parse items
10535 std::unique_ptr<AST::TupleStructItems> items
10536 = parse_tuple_struct_items ();
10537 if (items == nullptr)
10538 {
10539 Error error (lexer.peek_token ()->get_locus (),
10540 "failed to parse tuple struct items");
10541 add_error (std::move (error));
10542
10543 return nullptr;
10544 }
10545
10546 if (!skip_token (RIGHT_PAREN))
10547 {
10548 return nullptr;
10549 }
10550
10551 return std::unique_ptr<AST::TupleStructPattern> (
10552 new AST::TupleStructPattern (std::move (path),
10553 std::move (items)));
10554 }
10555 case LEFT_CURLY: {
10556 // struct
10557 lexer.skip_token ();
10558
10559 // parse elements (optional)
10560 AST::StructPatternElements elems = parse_struct_pattern_elems ();
10561
10562 if (!skip_token (RIGHT_CURLY))
10563 {
10564 return nullptr;
10565 }
10566
10567 return std::unique_ptr<AST::StructPattern> (
10568 new AST::StructPattern (std::move (path), t->get_locus (),
10569 std::move (elems)));
10570 }
10571 default:
10572 // assume path in expression
10573 return std::unique_ptr<AST::PathInExpression> (
10574 new AST::PathInExpression (std::move (path)));
10575 }
10576 }
10577 default:
10578 add_error (Error (t->get_locus (), "unexpected token %qs in pattern",
10579 t->get_token_description ()));
10580
10581 return nullptr;
10582 }
10583}
10584
10585// Parses a single or double reference pattern.
10586template <typename ManagedTokenSource>
10587std::unique_ptr<AST::ReferencePattern>
10588Parser<ManagedTokenSource>::parse_reference_pattern ()
10589{
10590 // parse double or single ref
10591 bool is_double_ref = false;
10592 const_TokenPtr t = lexer.peek_token ();
10593 switch (t->get_id ())
10594 {
10595 case AMP:
10596 // still false
10597 lexer.skip_token ();
10598 break;
10599 case LOGICAL_AND:
10600 is_double_ref = true;
10601 lexer.skip_token ();
10602 break;
10603 default:
10604 add_error (Error (t->get_locus (),
10605 "unexpected token %qs in reference pattern",
10606 t->get_token_description ()));
10607
10608 return nullptr;
10609 }
10610
10611 // parse mut (if it exists)
10612 bool is_mut = false;
10613 if (lexer.peek_token ()->get_id () == MUT)
10614 {
10615 is_mut = true;
10616 lexer.skip_token ();
10617 }
10618
10619 // parse pattern to get reference of (required)
94f2a1ce 10620 std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
32c8fb0e
JP
10621 if (pattern == nullptr)
10622 {
10623 Error error (lexer.peek_token ()->get_locus (),
10624 "failed to parse pattern in reference pattern");
10625 add_error (std::move (error));
10626
10627 // skip somewhere?
10628 return nullptr;
10629 }
10630
10631 return std::unique_ptr<AST::ReferencePattern> (
10632 new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref,
10633 t->get_locus ()));
10634}
10635
10636/* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if
10637 * only a single element with no commas. */
10638template <typename ManagedTokenSource>
10639std::unique_ptr<AST::Pattern>
10640Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern ()
10641{
80c68893 10642 location_t paren_locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
10643 skip_token (LEFT_PAREN);
10644
10645 // detect '..' token (ranged with no lower range)
10646 if (lexer.peek_token ()->get_id () == DOT_DOT)
10647 {
10648 lexer.skip_token ();
10649
10650 // parse new patterns while next token is a comma
10651 std::vector<std::unique_ptr<AST::Pattern>> patterns;
10652
10653 const_TokenPtr t = lexer.peek_token ();
10654 while (t->get_id () == COMMA)
10655 {
10656 lexer.skip_token ();
10657
10658 // break if next token is ')'
10659 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
10660 {
10661 break;
10662 }
10663
10664 // parse pattern, which is required
10665 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10666 if (pattern == nullptr)
10667 {
10668 Error error (
10669 lexer.peek_token ()->get_locus (),
10670 "failed to parse pattern inside ranged tuple pattern");
10671 add_error (std::move (error));
10672
10673 // skip somewhere?
10674 return nullptr;
10675 }
10676 patterns.push_back (std::move (pattern));
10677
10678 t = lexer.peek_token ();
10679 }
10680
10681 if (!skip_token (RIGHT_PAREN))
10682 {
10683 // skip somewhere?
10684 return nullptr;
10685 }
10686
10687 // create ranged tuple pattern items with only upper items
10688 std::unique_ptr<AST::TuplePatternItemsRanged> items (
10689 new AST::TuplePatternItemsRanged (
10690 std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns)));
10691 return std::unique_ptr<AST::TuplePattern> (
10692 new AST::TuplePattern (std::move (items), paren_locus));
10693 }
20529dff
OA
10694 else if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
10695 {
10696 skip_token (RIGHT_PAREN);
10697 auto items = std::unique_ptr<AST::TuplePatternItemsMultiple> (
10698 new AST::TuplePatternItemsMultiple (
10699 std::vector<std::unique_ptr<AST::Pattern>> ()));
10700 return std::unique_ptr<AST::TuplePattern> (
10701 new AST::TuplePattern (std::move (items), paren_locus));
10702 }
32c8fb0e
JP
10703
10704 // parse initial pattern (required)
10705 std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
10706 if (initial_pattern == nullptr)
10707 {
10708 Error error (lexer.peek_token ()->get_locus (),
10709 "failed to parse pattern in grouped or tuple pattern");
10710 add_error (std::move (error));
10711
10712 return nullptr;
10713 }
10714
10715 // branch on whether next token is a comma or not
10716 const_TokenPtr t = lexer.peek_token ();
10717 switch (t->get_id ())
10718 {
10719 case RIGHT_PAREN:
10720 // grouped pattern
10721 lexer.skip_token ();
10722
10723 return std::unique_ptr<AST::GroupedPattern> (
10724 new AST::GroupedPattern (std::move (initial_pattern), paren_locus));
10725 case COMMA: {
10726 // tuple pattern
10727 lexer.skip_token ();
10728
10729 // create vector of patterns
10730 std::vector<std::unique_ptr<AST::Pattern>> patterns;
10731 patterns.push_back (std::move (initial_pattern));
10732
10733 t = lexer.peek_token ();
10734 while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
10735 {
10736 // parse pattern (required)
10737 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10738 if (pattern == nullptr)
10739 {
10740 Error error (t->get_locus (),
10741 "failed to parse pattern in tuple pattern");
10742 add_error (std::move (error));
10743
10744 return nullptr;
10745 }
10746 patterns.push_back (std::move (pattern));
10747
10748 if (lexer.peek_token ()->get_id () != COMMA)
10749 break;
10750
10751 lexer.skip_token ();
10752 t = lexer.peek_token ();
10753 }
10754
10755 t = lexer.peek_token ();
10756 if (t->get_id () == RIGHT_PAREN)
10757 {
10758 // non-ranged tuple pattern
10759 lexer.skip_token ();
10760
10761 std::unique_ptr<AST::TuplePatternItemsMultiple> items (
10762 new AST::TuplePatternItemsMultiple (std::move (patterns)));
10763 return std::unique_ptr<AST::TuplePattern> (
10764 new AST::TuplePattern (std::move (items), paren_locus));
10765 }
10766 else if (t->get_id () == DOT_DOT)
10767 {
10768 // ranged tuple pattern
10769 lexer.skip_token ();
10770
10771 // parse upper patterns
10772 std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
10773 t = lexer.peek_token ();
10774 while (t->get_id () == COMMA)
10775 {
10776 lexer.skip_token ();
10777
10778 // break if end
10779 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
10780 break;
10781
10782 // parse pattern (required)
10783 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10784 if (pattern == nullptr)
10785 {
10786 Error error (lexer.peek_token ()->get_locus (),
10787 "failed to parse pattern in tuple pattern");
10788 add_error (std::move (error));
10789
10790 return nullptr;
10791 }
10792 upper_patterns.push_back (std::move (pattern));
10793
10794 t = lexer.peek_token ();
10795 }
10796
10797 if (!skip_token (RIGHT_PAREN))
10798 {
10799 return nullptr;
10800 }
10801
10802 std::unique_ptr<AST::TuplePatternItemsRanged> items (
10803 new AST::TuplePatternItemsRanged (std::move (patterns),
10804 std::move (upper_patterns)));
10805 return std::unique_ptr<AST::TuplePattern> (
10806 new AST::TuplePattern (std::move (items), paren_locus));
10807 }
10808 else
10809 {
10810 // some kind of error
10811 Error error (t->get_locus (),
10812 "failed to parse tuple pattern (probably) or maybe "
10813 "grouped pattern");
10814 add_error (std::move (error));
10815
10816 return nullptr;
10817 }
10818 }
10819 default:
10820 // error
10821 add_error (Error (t->get_locus (),
10822 "unrecognised token %qs in grouped or tuple pattern "
10823 "after first pattern",
10824 t->get_token_description ()));
10825
10826 return nullptr;
10827 }
10828}
10829
10830/* Parses a slice pattern that can match arrays or slices. Parses the square
10831 * brackets too. */
10832template <typename ManagedTokenSource>
10833std::unique_ptr<AST::SlicePattern>
10834Parser<ManagedTokenSource>::parse_slice_pattern ()
10835{
80c68893 10836 location_t square_locus = lexer.peek_token ()->get_locus ();
ba5445ad 10837 std::vector<std::unique_ptr<AST::Pattern>> patterns;
32c8fb0e
JP
10838 skip_token (LEFT_SQUARE);
10839
ba5445ad
PEP
10840 if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
10841 {
10842 skip_token (RIGHT_SQUARE);
10843 return std::unique_ptr<AST::SlicePattern> (
10844 new AST::SlicePattern (std::move (patterns), square_locus));
10845 }
10846
32c8fb0e
JP
10847 // parse initial pattern (required)
10848 std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
10849 if (initial_pattern == nullptr)
10850 {
10851 Error error (lexer.peek_token ()->get_locus (),
10852 "failed to parse initial pattern in slice pattern");
10853 add_error (std::move (error));
10854
10855 return nullptr;
10856 }
10857
32c8fb0e
JP
10858 patterns.push_back (std::move (initial_pattern));
10859
10860 const_TokenPtr t = lexer.peek_token ();
10861 while (t->get_id () == COMMA)
10862 {
10863 lexer.skip_token ();
10864
10865 // break if end bracket
10866 if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
10867 break;
10868
10869 // parse pattern (required)
10870 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10871 if (pattern == nullptr)
10872 {
10873 Error error (lexer.peek_token ()->get_locus (),
10874 "failed to parse pattern in slice pattern");
10875 add_error (std::move (error));
10876
10877 return nullptr;
10878 }
10879 patterns.push_back (std::move (pattern));
10880
10881 t = lexer.peek_token ();
10882 }
10883
10884 if (!skip_token (RIGHT_SQUARE))
10885 {
10886 return nullptr;
10887 }
10888
10889 return std::unique_ptr<AST::SlicePattern> (
10890 new AST::SlicePattern (std::move (patterns), square_locus));
10891}
10892
10893/* Parses an identifier pattern (pattern that binds a value matched to a
10894 * variable). */
10895template <typename ManagedTokenSource>
10896std::unique_ptr<AST::IdentifierPattern>
10897Parser<ManagedTokenSource>::parse_identifier_pattern ()
10898{
d991a3f1 10899 location_t locus = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
10900
10901 bool has_ref = false;
10902 if (lexer.peek_token ()->get_id () == REF)
10903 {
10904 has_ref = true;
10905 lexer.skip_token ();
10906
10907 // DEBUG
10908 rust_debug ("parsed ref in identifier pattern");
10909 }
10910
10911 bool has_mut = false;
10912 if (lexer.peek_token ()->get_id () == MUT)
10913 {
10914 has_mut = true;
10915 lexer.skip_token ();
10916 }
10917
10918 // parse identifier (required)
10919 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
10920 if (ident_tok == nullptr)
10921 {
10922 // skip somewhere?
10923 return nullptr;
10924 }
1c3a8fbb 10925 Identifier ident{ident_tok};
32c8fb0e
JP
10926
10927 // DEBUG
10928 rust_debug ("parsed identifier in identifier pattern");
10929
10930 // parse optional pattern binding thing
10931 std::unique_ptr<AST::Pattern> bind_pattern = nullptr;
10932 if (lexer.peek_token ()->get_id () == PATTERN_BIND)
10933 {
10934 lexer.skip_token ();
10935
10936 // parse required pattern to bind
10937 bind_pattern = parse_pattern ();
10938 if (bind_pattern == nullptr)
10939 {
10940 Error error (lexer.peek_token ()->get_locus (),
10941 "failed to parse pattern to bind in identifier pattern");
10942 add_error (std::move (error));
10943
10944 return nullptr;
10945 }
10946 }
10947
10948 // DEBUG
10949 rust_debug ("about to return identifier pattern");
10950
10951 return std::unique_ptr<AST::IdentifierPattern> (
10952 new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut,
10953 std::move (bind_pattern)));
10954}
10955
10956/* Parses a pattern that opens with an identifier. This includes identifier
10957 * patterns, path patterns (and derivatives such as struct patterns, tuple
10958 * struct patterns, and macro invocations), and ranges. */
10959template <typename ManagedTokenSource>
10960std::unique_ptr<AST::Pattern>
10961Parser<ManagedTokenSource>::parse_ident_leading_pattern ()
10962{
10963 // ensure first token is actually identifier
10964 const_TokenPtr initial_tok = lexer.peek_token ();
10965 if (initial_tok->get_id () != IDENTIFIER)
10966 {
10967 return nullptr;
10968 }
10969
10970 // save initial identifier as it may be useful (but don't skip)
10971 std::string initial_ident = initial_tok->get_str ();
10972
10973 // parse next tokens as a PathInExpression
10974 AST::PathInExpression path = parse_path_in_expression ();
10975
10976 // branch on next token
10977 const_TokenPtr t = lexer.peek_token ();
10978 switch (t->get_id ())
10979 {
10980 case EXCLAM:
10981 return parse_macro_invocation_partial (std::move (path), AST::AttrVec ());
10982 case LEFT_PAREN: {
10983 // tuple struct
10984 lexer.skip_token ();
10985
10986 // DEBUG
10987 rust_debug ("parsing tuple struct pattern");
10988
32c8fb0e
JP
10989 // parse items
10990 std::unique_ptr<AST::TupleStructItems> items
10991 = parse_tuple_struct_items ();
10992 if (items == nullptr)
10993 {
10994 Error error (lexer.peek_token ()->get_locus (),
10995 "failed to parse tuple struct items");
10996 add_error (std::move (error));
10997
10998 return nullptr;
10999 }
11000
11001 // DEBUG
11002 rust_debug ("successfully parsed tuple struct items");
11003
11004 if (!skip_token (RIGHT_PAREN))
11005 {
11006 return nullptr;
11007 }
11008
11009 // DEBUG
11010 rust_debug ("successfully parsed tuple struct pattern");
11011
11012 return std::unique_ptr<AST::TupleStructPattern> (
11013 new AST::TupleStructPattern (std::move (path), std::move (items)));
11014 }
11015 case LEFT_CURLY: {
11016 // struct
11017 lexer.skip_token ();
11018
11019 // parse elements (optional)
11020 AST::StructPatternElements elems = parse_struct_pattern_elems ();
11021
11022 if (!skip_token (RIGHT_CURLY))
11023 {
11024 return nullptr;
11025 }
11026
11027 // DEBUG
11028 rust_debug ("successfully parsed struct pattern");
11029
11030 return std::unique_ptr<AST::StructPattern> (
11031 new AST::StructPattern (std::move (path), initial_tok->get_locus (),
11032 std::move (elems)));
11033 }
11034 case DOT_DOT_EQ:
cc7ec392 11035 case DOT_DOT:
32c8fb0e
JP
11036 case ELLIPSIS: {
11037 // range
cc7ec392
PEP
11038 AST::RangeKind kind
11039 = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
32c8fb0e
JP
11040
11041 lexer.skip_token ();
11042
11043 std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
11044 new AST::RangePatternBoundPath (std::move (path)));
11045 std::unique_ptr<AST::RangePatternBound> upper_bound
11046 = parse_range_pattern_bound ();
11047
e5f3ad0f
OA
11048 return std::unique_ptr<AST::RangePattern> (
11049 new AST::RangePattern (std::move (lower_bound),
cc7ec392 11050 std::move (upper_bound), kind,
ab89ab37 11051 t->get_locus ()));
32c8fb0e
JP
11052 }
11053 case PATTERN_BIND: {
11054 // only allow on single-segment paths
11055 if (path.is_single_segment ())
11056 {
11057 // identifier with pattern bind
11058 lexer.skip_token ();
11059
11060 std::unique_ptr<AST::Pattern> bind_pattern = parse_pattern ();
11061 if (bind_pattern == nullptr)
11062 {
11063 Error error (
11064 t->get_locus (),
11065 "failed to parse pattern to bind to identifier pattern");
11066 add_error (std::move (error));
11067
11068 return nullptr;
11069 }
11070 return std::unique_ptr<AST::IdentifierPattern> (
11071 new AST::IdentifierPattern (std::move (initial_ident),
11072 initial_tok->get_locus (), false,
11073 false, std::move (bind_pattern)));
11074 }
11075 Error error (
11076 t->get_locus (),
11077 "failed to parse pattern bind to a path, not an identifier");
11078 add_error (std::move (error));
11079
11080 return nullptr;
11081 }
11082 default:
11083 // assume identifier if single segment
11084 if (path.is_single_segment ())
11085 {
11086 return std::unique_ptr<AST::IdentifierPattern> (
11087 new AST::IdentifierPattern (std::move (initial_ident),
11088 initial_tok->get_locus ()));
11089 }
11090 // return path otherwise
11091 return std::unique_ptr<AST::PathInExpression> (
11092 new AST::PathInExpression (std::move (path)));
11093 }
11094}
11095
11096// Parses tuple struct items if they exist. Does not parse parentheses.
11097template <typename ManagedTokenSource>
11098std::unique_ptr<AST::TupleStructItems>
11099Parser<ManagedTokenSource>::parse_tuple_struct_items ()
11100{
11101 std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
11102
11103 // DEBUG
11104 rust_debug ("started parsing tuple struct items");
11105
11106 // check for '..' at front
11107 if (lexer.peek_token ()->get_id () == DOT_DOT)
11108 {
11109 // only parse upper patterns
11110 lexer.skip_token ();
11111
11112 // DEBUG
11113 rust_debug ("'..' at front in tuple struct items detected");
11114
11115 std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
11116
11117 const_TokenPtr t = lexer.peek_token ();
11118 while (t->get_id () == COMMA)
11119 {
11120 lexer.skip_token ();
11121
11122 // break if right paren
11123 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
11124 break;
11125
11126 // parse pattern, which is now required
11127 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11128 if (pattern == nullptr)
11129 {
11130 Error error (lexer.peek_token ()->get_locus (),
11131 "failed to parse pattern in tuple struct items");
11132 add_error (std::move (error));
11133
11134 return nullptr;
11135 }
11136 upper_patterns.push_back (std::move (pattern));
11137
11138 t = lexer.peek_token ();
11139 }
11140
11141 // DEBUG
11142 rust_debug (
11143 "finished parsing tuple struct items ranged (upper/none only)");
11144
11145 return std::unique_ptr<AST::TupleStructItemsRange> (
11146 new AST::TupleStructItemsRange (std::move (lower_patterns),
11147 std::move (upper_patterns)));
11148 }
11149
11150 // has at least some lower patterns
11151 const_TokenPtr t = lexer.peek_token ();
11152 while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
11153 {
11154 // DEBUG
11155 rust_debug ("about to parse pattern in tuple struct items");
11156
11157 // parse pattern, which is required
11158 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11159 if (pattern == nullptr)
11160 {
11161 Error error (t->get_locus (),
11162 "failed to parse pattern in tuple struct items");
11163 add_error (std::move (error));
11164
11165 return nullptr;
11166 }
11167 lower_patterns.push_back (std::move (pattern));
11168
11169 // DEBUG
11170 rust_debug ("successfully parsed pattern in tuple struct items");
11171
11172 if (lexer.peek_token ()->get_id () != COMMA)
11173 {
11174 // DEBUG
11175 rust_debug ("broke out of parsing patterns in tuple struct "
11176 "items as no comma");
11177
11178 break;
11179 }
11180 lexer.skip_token ();
11181 t = lexer.peek_token ();
11182 }
11183
11184 // branch on next token
11185 t = lexer.peek_token ();
11186 switch (t->get_id ())
11187 {
11188 case RIGHT_PAREN:
11189 return std::unique_ptr<AST::TupleStructItemsNoRange> (
11190 new AST::TupleStructItemsNoRange (std::move (lower_patterns)));
11191 case DOT_DOT: {
11192 // has an upper range that must be parsed separately
11193 lexer.skip_token ();
11194
11195 std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
11196
11197 t = lexer.peek_token ();
11198 while (t->get_id () == COMMA)
11199 {
11200 lexer.skip_token ();
11201
11202 // break if next token is right paren
11203 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
11204 break;
11205
11206 // parse pattern, which is required
11207 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11208 if (pattern == nullptr)
11209 {
11210 Error error (lexer.peek_token ()->get_locus (),
11211 "failed to parse pattern in tuple struct items");
11212 add_error (std::move (error));
11213
11214 return nullptr;
11215 }
11216 upper_patterns.push_back (std::move (pattern));
11217
11218 t = lexer.peek_token ();
11219 }
11220
11221 return std::unique_ptr<AST::TupleStructItemsRange> (
11222 new AST::TupleStructItemsRange (std::move (lower_patterns),
11223 std::move (upper_patterns)));
11224 }
11225 default:
11226 // error
11227 add_error (Error (t->get_locus (),
11228 "unexpected token %qs in tuple struct items",
11229 t->get_token_description ()));
11230
11231 return nullptr;
11232 }
11233}
11234
11235// Parses struct pattern elements if they exist.
11236template <typename ManagedTokenSource>
11237AST::StructPatternElements
11238Parser<ManagedTokenSource>::parse_struct_pattern_elems ()
11239{
11240 std::vector<std::unique_ptr<AST::StructPatternField>> fields;
11241
11242 AST::AttrVec etc_attrs;
11243 bool has_etc = false;
11244
11245 // try parsing struct pattern fields
11246 const_TokenPtr t = lexer.peek_token ();
11247 while (t->get_id () != RIGHT_CURLY)
11248 {
11249 AST::AttrVec outer_attrs = parse_outer_attributes ();
11250
11251 // parse etc (must be last in struct pattern, so breaks)
11252 if (lexer.peek_token ()->get_id () == DOT_DOT)
11253 {
11254 lexer.skip_token ();
11255 etc_attrs = std::move (outer_attrs);
11256 has_etc = true;
11257 break;
11258 }
11259
11260 std::unique_ptr<AST::StructPatternField> field
11261 = parse_struct_pattern_field_partial (std::move (outer_attrs));
11262 if (field == nullptr)
11263 {
11264 Error error (lexer.peek_token ()->get_locus (),
11265 "failed to parse struct pattern field");
11266 add_error (std::move (error));
11267
11268 // skip after somewhere?
11269 return AST::StructPatternElements::create_empty ();
11270 }
11271 fields.push_back (std::move (field));
11272
11273 if (lexer.peek_token ()->get_id () != COMMA)
11274 break;
11275
11276 // skip comma
11277 lexer.skip_token ();
11278 t = lexer.peek_token ();
11279 }
11280
11281 if (has_etc)
11282 return AST::StructPatternElements (std::move (fields),
11283 std::move (etc_attrs));
11284 else
11285 return AST::StructPatternElements (std::move (fields));
11286}
11287
11288/* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
11289 * identifier). */
11290template <typename ManagedTokenSource>
11291std::unique_ptr<AST::StructPatternField>
11292Parser<ManagedTokenSource>::parse_struct_pattern_field ()
11293{
11294 // parse outer attributes (if they exist)
11295 AST::AttrVec outer_attrs = parse_outer_attributes ();
11296
11297 return parse_struct_pattern_field_partial (std::move (outer_attrs));
11298}
11299
11300/* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
11301 * identifier), with outer attributes passed in. */
11302template <typename ManagedTokenSource>
11303std::unique_ptr<AST::StructPatternField>
11304Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
11305 AST::AttrVec outer_attrs)
11306{
11307 // branch based on next token
11308 const_TokenPtr t = lexer.peek_token ();
11309 switch (t->get_id ())
11310 {
11311 case INT_LITERAL: {
11312 // tuple index
11313 std::string index_str = t->get_str ();
11314 int index = atoi (index_str.c_str ());
11315
6f15aac2
JD
11316 lexer.skip_token ();
11317
32c8fb0e
JP
11318 if (!skip_token (COLON))
11319 {
11320 return nullptr;
11321 }
11322
11323 // parse required pattern
11324 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11325 if (pattern == nullptr)
11326 {
11327 Error error (
11328 t->get_locus (),
11329 "failed to parse pattern in tuple index struct pattern field");
11330 add_error (std::move (error));
11331
11332 return nullptr;
11333 }
11334
11335 return std::unique_ptr<AST::StructPatternFieldTuplePat> (
11336 new AST::StructPatternFieldTuplePat (index, std::move (pattern),
11337 std::move (outer_attrs),
11338 t->get_locus ()));
11339 }
11340 case IDENTIFIER:
11341 // identifier-pattern OR only identifier
11342 // branch on next token
11343 switch (lexer.peek_token (1)->get_id ())
11344 {
11345 case COLON: {
11346 // identifier-pattern
1c3a8fbb 11347 Identifier ident{t};
32c8fb0e
JP
11348 lexer.skip_token ();
11349
11350 skip_token (COLON);
11351
11352 // parse required pattern
11353 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11354 if (pattern == nullptr)
11355 {
11356 Error error (t->get_locus (),
11357 "failed to parse pattern in struct pattern field");
11358 add_error (std::move (error));
11359
11360 return nullptr;
11361 }
11362
11363 return std::unique_ptr<AST::StructPatternFieldIdentPat> (
11364 new AST::StructPatternFieldIdentPat (std::move (ident),
11365 std::move (pattern),
11366 std::move (outer_attrs),
11367 t->get_locus ()));
11368 }
11369 case COMMA:
11370 case RIGHT_CURLY: {
11371 // identifier only
1c3a8fbb 11372 Identifier ident = {t};
32c8fb0e
JP
11373 lexer.skip_token ();
11374
11375 return std::unique_ptr<AST::StructPatternFieldIdent> (
11376 new AST::StructPatternFieldIdent (std::move (ident), false, false,
11377 std::move (outer_attrs),
11378 t->get_locus ()));
11379 }
11380 default:
11381 // error
11382 add_error (Error (t->get_locus (),
11383 "unrecognised token %qs in struct pattern field",
11384 t->get_token_description ()));
11385
11386 return nullptr;
11387 }
11388 case REF:
11389 case MUT: {
11390 // only identifier
11391 bool has_ref = false;
11392 if (t->get_id () == REF)
11393 {
11394 has_ref = true;
11395 lexer.skip_token ();
11396 }
11397
11398 bool has_mut = false;
11399 if (lexer.peek_token ()->get_id () == MUT)
11400 {
11401 has_mut = true;
11402 lexer.skip_token ();
11403 }
11404
11405 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
11406 if (ident_tok == nullptr)
11407 {
11408 return nullptr;
11409 }
1c3a8fbb 11410 Identifier ident{ident_tok};
32c8fb0e
JP
11411
11412 return std::unique_ptr<AST::StructPatternFieldIdent> (
11413 new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut,
11414 std::move (outer_attrs),
11415 t->get_locus ()));
11416 }
11417 default:
11418 // not necessarily an error
11419 return nullptr;
11420 }
11421}
11422
32c8fb0e
JP
11423/* Parses a statement or expression (depending on whether a trailing semicolon
11424 * exists). Useful for block expressions where it cannot be determined through
11425 * lookahead whether it is a statement or expression to be parsed. */
11426template <typename ManagedTokenSource>
11427ExprOrStmt
48408712 11428Parser<ManagedTokenSource>::parse_stmt_or_expr ()
32c8fb0e
JP
11429{
11430 // quick exit for empty statement
11431 const_TokenPtr t = lexer.peek_token ();
11432 if (t->get_id () == SEMICOLON)
11433 {
11434 lexer.skip_token ();
11435 std::unique_ptr<AST::EmptyStmt> stmt (
11436 new AST::EmptyStmt (t->get_locus ()));
11437 return ExprOrStmt (std::move (stmt));
11438 }
11439
11440 // parse outer attributes
11441 AST::AttrVec outer_attrs = parse_outer_attributes ();
48408712
MJ
11442 ParseRestrictions restrictions;
11443 restrictions.expr_can_be_stmt = true;
8bc4ce7c 11444 std::unique_ptr<AST::Expr> expr;
32c8fb0e
JP
11445
11446 // parsing this will be annoying because of the many different possibilities
11447 /* best may be just to copy paste in parse_item switch, and failing that try
11448 * to parse outer attributes, and then pass them in to either a let
11449 * statement or (fallback) expression statement. */
11450 // FIXME: think of a way to do this without such a large switch?
11451
11452 /* FIXME: for expressions at least, the only way that they can really be
11453 * parsed properly in this way is if they don't support operators on them.
11454 * They must be pratt-parsed otherwise. As such due to composability, only
11455 * explicit statements will have special cases here. This should roughly
11456 * correspond to "expr-with-block", but this warning is here in case it
11457 * isn't the case. */
11458 t = lexer.peek_token ();
11459 switch (t->get_id ())
11460 {
11461 case LET: {
11462 // let statement
11463 std::unique_ptr<AST::LetStmt> stmt (
11464 parse_let_stmt (std::move (outer_attrs)));
11465 return ExprOrStmt (std::move (stmt));
11466 }
11467 case PUB:
11468 case MOD:
7f631967 11469 case EXTERN_KW:
32c8fb0e 11470 case USE:
7f631967 11471 case FN_KW:
32c8fb0e 11472 case TYPE:
7f631967
PEP
11473 case STRUCT_KW:
11474 case ENUM_KW:
32c8fb0e 11475 case CONST:
7f631967 11476 case STATIC_KW:
22128105 11477 case AUTO:
32c8fb0e
JP
11478 case TRAIT:
11479 case IMPL: {
11480 std::unique_ptr<AST::VisItem> item (
11481 parse_vis_item (std::move (outer_attrs)));
11482 return ExprOrStmt (std::move (item));
11483 }
11484 /* TODO: implement union keyword but not really because of
11485 * context-dependence crappy hack way to parse a union written below to
11486 * separate it from the good code. */
11487 // case UNION:
11488 case UNSAFE: { // maybe - unsafe traits are a thing
11489 /* if any of these (should be all possible VisItem prefixes), parse a
11490 * VisItem - can't parse item because would require reparsing outer
11491 * attributes */
11492 const_TokenPtr t2 = lexer.peek_token (1);
11493 switch (t2->get_id ())
11494 {
11495 case LEFT_CURLY: {
48408712 11496 // unsafe block: parse as expression
8bc4ce7c 11497 expr = parse_expr (std::move (outer_attrs), restrictions);
48408712 11498 break;
32c8fb0e 11499 }
22128105 11500 case AUTO:
32c8fb0e
JP
11501 case TRAIT: {
11502 // unsafe trait
11503 std::unique_ptr<AST::VisItem> item (
11504 parse_vis_item (std::move (outer_attrs)));
11505 return ExprOrStmt (std::move (item));
11506 }
7f631967
PEP
11507 case EXTERN_KW:
11508 case FN_KW: {
32c8fb0e
JP
11509 // unsafe function
11510 std::unique_ptr<AST::VisItem> item (
11511 parse_vis_item (std::move (outer_attrs)));
11512 return ExprOrStmt (std::move (item));
11513 }
11514 case IMPL: {
11515 // unsafe trait impl
11516 std::unique_ptr<AST::VisItem> item (
11517 parse_vis_item (std::move (outer_attrs)));
11518 return ExprOrStmt (std::move (item));
11519 }
11520 default:
11521 add_error (Error (t2->get_locus (),
11522 "unrecognised token %qs after parsing unsafe - "
11523 "expected beginning of expression or statement",
11524 t->get_token_description ()));
11525
11526 // skip somewhere?
11527 return ExprOrStmt::create_error ();
11528 }
48408712 11529 break;
32c8fb0e
JP
11530 }
11531 /* FIXME: this is either a macro invocation or macro invocation semi.
11532 * start parsing to determine which one it is. */
32c8fb0e 11533 // FIXME: old code there
32c8fb0e 11534
32c8fb0e
JP
11535 // crappy hack to do union "keyword"
11536 case IDENTIFIER:
28652f21 11537 if (t->get_str () == Values::WeakKeywords::UNION
32c8fb0e
JP
11538 && lexer.peek_token (1)->get_id () == IDENTIFIER)
11539 {
11540 std::unique_ptr<AST::VisItem> item (
11541 parse_vis_item (std::move (outer_attrs)));
11542 return ExprOrStmt (std::move (item));
11543 // or should this go straight to parsing union?
11544 }
28652f21 11545 else if (t->get_str () == Values::WeakKeywords::MACRO_RULES
8bc4ce7c 11546 && lexer.peek_token (1)->get_id () == EXCLAM)
32c8fb0e
JP
11547 {
11548 // macro_rules! macro item
e1394230
RT
11549 std::unique_ptr<AST::Item> item (
11550 parse_macro_rules_def (std::move (outer_attrs)));
32c8fb0e
JP
11551 return ExprOrStmt (std::move (item));
11552 }
8bc4ce7c
MJ
11553 gcc_fallthrough ();
11554 case SUPER:
11555 case SELF:
11556 case SELF_ALIAS:
11557 case CRATE:
11558 case SCOPE_RESOLUTION:
11559 case DOLLAR_SIGN: {
11560 AST::PathInExpression path = parse_path_in_expression ();
11561 std::unique_ptr<AST::Expr> null_denotation;
11562
11563 if (lexer.peek_token ()->get_id () == EXCLAM)
11564 {
11565 std::unique_ptr<AST::MacroInvocation> invoc
11566 = parse_macro_invocation_partial (std::move (path),
11567 std::move (outer_attrs));
11568
11569 if (restrictions.consume_semi && maybe_skip_token (SEMICOLON))
11570 {
11571 invoc->add_semicolon ();
11572 // Macro invocation with semicolon.
11573 return ExprOrStmt (
11574 std::unique_ptr<AST::Stmt> (std::move (invoc)));
11575 }
11576
11577 TokenId after_macro = lexer.peek_token ()->get_id ();
11578
11579 if (invoc->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
11580 == AST::CURLY
11581 && after_macro != DOT && after_macro != QUESTION_MARK)
11582 {
11583 rust_debug ("braced macro statement");
11584 return ExprOrStmt (
11585 std::unique_ptr<AST::Stmt> (std::move (invoc)));
11586 }
11587
11588 null_denotation = std::move (invoc);
11589 }
11590 else
11591 {
11592 null_denotation
11593 = null_denotation_path (std::move (path), {}, restrictions);
11594 }
11595
11596 expr = left_denotations (std::move (null_denotation), LBP_LOWEST,
11597 std::move (outer_attrs), restrictions);
11598 break;
11599 }
48408712 11600 default:
8bc4ce7c
MJ
11601 /* expression statement or expression itself - parse
11602 * expression then make it statement if semi afterwards */
11603 expr = parse_expr (std::move (outer_attrs), restrictions);
48408712
MJ
11604 break;
11605 }
32c8fb0e 11606
48408712
MJ
11607 const_TokenPtr after_expr = lexer.peek_token ();
11608 if (after_expr->get_id () == SEMICOLON)
11609 {
11610 // must be expression statement
11611 lexer.skip_token ();
32c8fb0e 11612
48408712
MJ
11613 if (expr)
11614 {
11615 std::unique_ptr<AST::ExprStmt> stmt (
11616 new AST::ExprStmt (std::move (expr), t->get_locus (), true));
11617 return ExprOrStmt (std::move (stmt));
32c8fb0e 11618 }
48408712
MJ
11619 else
11620 {
11621 return ExprOrStmt::create_error ();
11622 }
11623 }
32c8fb0e 11624
48408712
MJ
11625 if (expr && !expr->is_expr_without_block ()
11626 && after_expr->get_id () != RIGHT_CURLY)
11627 {
11628 // block expression statement.
11629 std::unique_ptr<AST::ExprStmt> stmt (
11630 new AST::ExprStmt (std::move (expr), t->get_locus (), false));
11631 return ExprOrStmt (std::move (stmt));
32c8fb0e 11632 }
48408712
MJ
11633
11634 // return expression
11635 return ExprOrStmt (std::move (expr));
32c8fb0e
JP
11636}
11637
32c8fb0e
JP
11638// Parses a struct expression field.
11639template <typename ManagedTokenSource>
11640std::unique_ptr<AST::StructExprField>
11641Parser<ManagedTokenSource>::parse_struct_expr_field ()
11642{
fc1712be 11643 AST::AttrVec outer_attrs = parse_outer_attributes ();
32c8fb0e
JP
11644 const_TokenPtr t = lexer.peek_token ();
11645 switch (t->get_id ())
11646 {
11647 case IDENTIFIER:
11648 if (lexer.peek_token (1)->get_id () == COLON)
11649 {
11650 // struct expr field with identifier and expr
1c3a8fbb 11651 Identifier ident = {t};
32c8fb0e
JP
11652 lexer.skip_token (1);
11653
11654 // parse expression (required)
11655 std::unique_ptr<AST::Expr> expr = parse_expr ();
11656 if (expr == nullptr)
11657 {
11658 Error error (t->get_locus (),
11659 "failed to parse struct expression field with "
11660 "identifier and expression");
11661 add_error (std::move (error));
11662
11663 return nullptr;
11664 }
11665
11666 return std::unique_ptr<AST::StructExprFieldIdentifierValue> (
11667 new AST::StructExprFieldIdentifierValue (std::move (ident),
11668 std::move (expr),
fc1712be 11669 std::move (outer_attrs),
32c8fb0e
JP
11670 t->get_locus ()));
11671 }
11672 else
11673 {
11674 // struct expr field with identifier only
1c3a8fbb 11675 Identifier ident{t};
32c8fb0e
JP
11676 lexer.skip_token ();
11677
11678 return std::unique_ptr<AST::StructExprFieldIdentifier> (
11679 new AST::StructExprFieldIdentifier (std::move (ident),
fc1712be 11680 std::move (outer_attrs),
32c8fb0e
JP
11681 t->get_locus ()));
11682 }
11683 case INT_LITERAL: {
11684 // parse tuple index field
11685 int index = atoi (t->get_str ().c_str ());
11686 lexer.skip_token ();
11687
11688 if (!skip_token (COLON))
11689 {
11690 // skip somewhere?
11691 return nullptr;
11692 }
11693
11694 // parse field expression (required)
11695 std::unique_ptr<AST::Expr> expr = parse_expr ();
11696 if (expr == nullptr)
11697 {
11698 Error error (t->get_locus (),
11699 "failed to parse expr in struct (or enum) expr "
11700 "field with tuple index");
11701 add_error (std::move (error));
11702
11703 return nullptr;
11704 }
11705
11706 return std::unique_ptr<AST::StructExprFieldIndexValue> (
11707 new AST::StructExprFieldIndexValue (index, std::move (expr),
fc1712be 11708 std::move (outer_attrs),
32c8fb0e
JP
11709 t->get_locus ()));
11710 }
11711 case DOT_DOT:
11712 /* this is a struct base and can't be parsed here, so just return
11713 * nothing without erroring */
11714
11715 return nullptr;
11716 default:
11717 add_error (
11718 Error (t->get_locus (),
11719 "unrecognised token %qs as first token of struct expr field - "
11720 "expected identifier or integer literal",
11721 t->get_token_description ()));
11722
11723 return nullptr;
11724 }
11725}
11726
32c8fb0e
JP
11727// "Unexpected token" panic mode - flags gcc error at unexpected token
11728template <typename ManagedTokenSource>
11729void
11730Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t)
11731{
11732 Error error (t->get_locus (), "unexpected token %qs\n",
11733 t->get_token_description ());
11734 add_error (std::move (error));
11735}
11736
11737/* Crappy "error recovery" performed after error by skipping tokens until a
11738 * semi-colon is found */
11739template <typename ManagedTokenSource>
11740void
11741Parser<ManagedTokenSource>::skip_after_semicolon ()
11742{
11743 const_TokenPtr t = lexer.peek_token ();
11744
11745 while (t->get_id () != END_OF_FILE && t->get_id () != SEMICOLON)
11746 {
11747 lexer.skip_token ();
11748 t = lexer.peek_token ();
11749 }
11750
11751 if (t->get_id () == SEMICOLON)
11752 lexer.skip_token ();
11753}
11754
007248a2
OA
11755/* Skips the current token */
11756template <typename ManagedTokenSource>
11757void
11758Parser<ManagedTokenSource>::skip_token ()
11759{
11760 lexer.skip_token ();
11761}
11762
32c8fb0e
JP
11763/* Checks if current token has inputted id - skips it and returns true if so,
11764 * diagnoses an error and returns false otherwise. */
11765template <typename ManagedTokenSource>
11766bool
11767Parser<ManagedTokenSource>::skip_token (TokenId token_id)
11768{
11769 return expect_token (token_id) != const_TokenPtr ();
11770}
11771
497632d1
OA
11772/* Checks if current token is similar to inputted token - skips it and returns
11773 * true if so, diagnoses an error and returns false otherwise. */
11774template <typename ManagedTokenSource>
11775bool
11776Parser<ManagedTokenSource>::skip_token (const_TokenPtr token)
11777{
11778 return expect_token (token) != const_TokenPtr ();
11779}
11780
32c8fb0e
JP
11781/* Checks if current token has inputted id - skips it and returns true if so,
11782 * returns false otherwise without diagnosing an error */
11783template <typename ManagedTokenSource>
11784bool
11785Parser<ManagedTokenSource>::maybe_skip_token (TokenId token_id)
11786{
11787 if (lexer.peek_token ()->get_id () != token_id)
11788 return false;
11789 else
11790 return skip_token (token_id);
11791}
11792
11793/* Checks the current token - if id is same as expected, skips and returns it,
11794 * otherwise diagnoses error and returns null. */
11795template <typename ManagedTokenSource>
11796const_TokenPtr
11797Parser<ManagedTokenSource>::expect_token (TokenId token_id)
11798{
11799 const_TokenPtr t = lexer.peek_token ();
11800 if (t->get_id () == token_id)
11801 {
11802 lexer.skip_token ();
11803 return t;
11804 }
11805 else
11806 {
11807 Error error (t->get_locus (), "expecting %qs but %qs found",
11808 get_token_description (token_id),
11809 t->get_token_description ());
11810 add_error (std::move (error));
11811
11812 return const_TokenPtr ();
11813 }
11814}
11815
497632d1
OA
11816/* Checks the current token - if same as expected, skips and returns it,
11817 * otherwise diagnoses error and returns null. */
11818template <typename ManagedTokenSource>
11819const_TokenPtr
11820Parser<ManagedTokenSource>::expect_token (const_TokenPtr token_expect)
11821{
11822 const_TokenPtr t = lexer.peek_token ();
11823 if (t->get_id () == token_expect->get_id ()
11824 && (!t->should_have_str () || t->get_str () == token_expect->get_str ()))
11825 {
11826 lexer.skip_token ();
11827 return t;
11828 }
11829 else
11830 {
11831 Error error (t->get_locus (), "expecting %qs but %qs found",
11832 token_expect->get_token_description (),
11833 t->get_token_description ());
11834 add_error (std::move (error));
11835
11836 return const_TokenPtr ();
11837 }
11838}
11839
32c8fb0e
JP
11840// Skips all tokens until EOF or }. Don't use.
11841template <typename ManagedTokenSource>
11842void
11843Parser<ManagedTokenSource>::skip_after_end ()
11844{
11845 const_TokenPtr t = lexer.peek_token ();
11846
11847 while (t->get_id () != END_OF_FILE && t->get_id () != RIGHT_CURLY)
11848 {
11849 lexer.skip_token ();
11850 t = lexer.peek_token ();
11851 }
11852
11853 if (t->get_id () == RIGHT_CURLY)
11854 {
11855 lexer.skip_token ();
11856 }
11857}
11858
11859/* A slightly more aware error-handler that skips all tokens until it reaches
11860 * the end of the block scope (i.e. when left curly brackets = right curly
11861 * brackets). Note: assumes currently in the middle of a block. Use
11862 * skip_after_next_block to skip based on the assumption that the block
11863 * has not been entered yet. */
11864template <typename ManagedTokenSource>
11865void
11866Parser<ManagedTokenSource>::skip_after_end_block ()
11867{
11868 const_TokenPtr t = lexer.peek_token ();
11869 int curly_count = 1;
11870
11871 while (curly_count > 0 && t->get_id () != END_OF_FILE)
11872 {
11873 switch (t->get_id ())
11874 {
11875 case LEFT_CURLY:
11876 curly_count++;
11877 break;
11878 case RIGHT_CURLY:
11879 curly_count--;
11880 break;
11881 default:
11882 break;
11883 }
11884 lexer.skip_token ();
11885 t = lexer.peek_token ();
11886 }
11887}
11888
11889/* Skips tokens until the end of the next block. i.e. assumes that the block
11890 * has not been entered yet. */
11891template <typename ManagedTokenSource>
11892void
11893Parser<ManagedTokenSource>::skip_after_next_block ()
11894{
11895 const_TokenPtr t = lexer.peek_token ();
11896
11897 // initial loop - skip until EOF if no left curlies encountered
11898 while (t->get_id () != END_OF_FILE && t->get_id () != LEFT_CURLY)
11899 {
11900 lexer.skip_token ();
11901
11902 t = lexer.peek_token ();
11903 }
11904
11905 // if next token is left, skip it and then skip after the block ends
11906 if (t->get_id () == LEFT_CURLY)
11907 {
11908 lexer.skip_token ();
11909
11910 skip_after_end_block ();
11911 }
11912 // otherwise, do nothing as EOF
11913}
11914
11915/* Skips all tokens until ] (the end of an attribute) - does not skip the ]
11916 * (as designed for attribute body use) */
11917template <typename ManagedTokenSource>
11918void
11919Parser<ManagedTokenSource>::skip_after_end_attribute ()
11920{
11921 const_TokenPtr t = lexer.peek_token ();
11922
11923 while (t->get_id () != RIGHT_SQUARE)
11924 {
11925 lexer.skip_token ();
11926 t = lexer.peek_token ();
11927 }
11928
11929 // Don't skip the RIGHT_SQUARE token
11930}
11931
11932/* Pratt parser impl of parse_expr. FIXME: this is only provisional and
48408712 11933 * probably will be changed. */
32c8fb0e
JP
11934template <typename ManagedTokenSource>
11935std::unique_ptr<AST::Expr>
11936Parser<ManagedTokenSource>::parse_expr (int right_binding_power,
11937 AST::AttrVec outer_attrs,
11938 ParseRestrictions restrictions)
11939{
11940 const_TokenPtr current_token = lexer.peek_token ();
11941 // Special hack because we are allowed to return nullptr, in that case we
11942 // don't want to skip the token, since we don't actually parse it. But if
11943 // null isn't allowed it indicates an error, and we want to skip past that.
11944 // So return early if it is one of the tokens that ends an expression
11945 // (or at least cannot start a new expression).
11946 if (restrictions.expr_can_be_null)
11947 {
11948 TokenId id = current_token->get_id ();
11949 if (id == SEMICOLON || id == RIGHT_PAREN || id == RIGHT_CURLY
dff99b74 11950 || id == RIGHT_SQUARE || id == COMMA || id == LEFT_CURLY)
32c8fb0e
JP
11951 return nullptr;
11952 }
29fed556 11953
11954 if (current_token->get_id () == LEFT_SHIFT)
11955 {
11956 lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
11957 current_token = lexer.peek_token ();
11958 }
11959
32c8fb0e
JP
11960 lexer.skip_token ();
11961
8bc4ce7c
MJ
11962 ParseRestrictions null_denotation_restrictions = restrictions;
11963 null_denotation_restrictions.expr_can_be_stmt = false;
48408712 11964
32c8fb0e
JP
11965 // parse null denotation (unary part of expression)
11966 std::unique_ptr<AST::Expr> expr
8bc4ce7c
MJ
11967 = null_denotation (current_token, {}, null_denotation_restrictions);
11968
11969 return left_denotations (std::move (expr), right_binding_power,
11970 std::move (outer_attrs), restrictions);
11971}
32c8fb0e 11972
8bc4ce7c
MJ
11973template <typename ManagedTokenSource>
11974std::unique_ptr<AST::Expr>
11975Parser<ManagedTokenSource>::left_denotations (std::unique_ptr<AST::Expr> expr,
11976 int right_binding_power,
11977 AST::AttrVec outer_attrs,
11978 ParseRestrictions restrictions)
11979{
32c8fb0e
JP
11980 if (expr == nullptr)
11981 {
11982 // DEBUG
11983 rust_debug ("null denotation is null; returning null for parse_expr");
11984 return nullptr;
11985 }
11986
8bc4ce7c 11987 const_TokenPtr current_token = lexer.peek_token ();
48408712 11988
8bc4ce7c 11989 if (restrictions.expr_can_be_stmt && !expr->is_expr_without_block ()
48408712
MJ
11990 && current_token->get_id () != DOT
11991 && current_token->get_id () != QUESTION_MARK)
11992 {
11993 rust_debug ("statement expression with block");
11994 expr->set_outer_attrs (std::move (outer_attrs));
11995 return expr;
11996 }
11997
8bc4ce7c
MJ
11998 restrictions.expr_can_be_stmt = false;
11999
32c8fb0e 12000 // stop parsing if find lower priority token - parse higher priority first
48408712 12001 while (right_binding_power < left_binding_power (current_token))
32c8fb0e 12002 {
32c8fb0e
JP
12003 lexer.skip_token ();
12004
48408712 12005 // FIXME attributes should generally be applied to the null denotation.
32c8fb0e
JP
12006 expr = left_denotation (current_token, std::move (expr),
12007 std::move (outer_attrs), restrictions);
12008
12009 if (expr == nullptr)
12010 {
12011 // DEBUG
12012 rust_debug ("left denotation is null; returning null for parse_expr");
12013
12014 return nullptr;
12015 }
48408712
MJ
12016
12017 current_token = lexer.peek_token ();
32c8fb0e
JP
12018 }
12019
12020 return expr;
12021}
12022
12023// Parse expression with lowest left binding power.
12024template <typename ManagedTokenSource>
12025std::unique_ptr<AST::Expr>
12026Parser<ManagedTokenSource>::parse_expr (AST::AttrVec outer_attrs,
12027 ParseRestrictions restrictions)
12028{
12029 return parse_expr (LBP_LOWEST, std::move (outer_attrs), restrictions);
12030}
12031
48408712 12032/* Determines action to take when finding token at beginning of expression. */
32c8fb0e
JP
12033template <typename ManagedTokenSource>
12034std::unique_ptr<AST::Expr>
12035Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok,
12036 AST::AttrVec outer_attrs,
12037 ParseRestrictions restrictions)
12038{
12039 /* note: tok is previous character in input stream, not current one, as
12040 * parse_expr skips it before passing it in */
12041
12042 /* as a Pratt parser (which works by decomposing expressions into a null
12043 * denotation and then a left denotation), null denotations handle primaries
12044 * and unary operands (but only prefix unary operands) */
12045
12046 switch (tok->get_id ())
12047 {
8bc4ce7c
MJ
12048 case IDENTIFIER:
12049 case SELF:
12050 case SELF_ALIAS:
12051 case DOLLAR_SIGN:
12052 case CRATE:
12053 case SUPER: {
32c8fb0e
JP
12054 // DEBUG
12055 rust_debug ("beginning null denotation identifier handling");
12056
12057 /* best option: parse as path, then extract identifier, macro,
12058 * struct/enum, or just path info from it */
12059 AST::PathInExpression path = parse_path_in_expression_pratt (tok);
12060
8bc4ce7c
MJ
12061 return null_denotation_path (std::move (path), std::move (outer_attrs),
12062 restrictions);
12063 }
12064 case SCOPE_RESOLUTION: {
12065 // TODO: fix: this is for global paths, i.e. std::string::whatever
12066 Error error (tok->get_locus (),
12067 "found null denotation scope resolution operator, and "
12068 "have not written handling for it");
12069 add_error (std::move (error));
32c8fb0e 12070
8bc4ce7c
MJ
12071 return nullptr;
12072 }
12073 default:
12074 return null_denotation_not_path (std::move (tok), std::move (outer_attrs),
12075 restrictions);
12076 }
12077}
12078
12079// Handling of expresions that start with a path for `null_denotation`.
12080template <typename ManagedTokenSource>
12081std::unique_ptr<AST::Expr>
12082Parser<ManagedTokenSource>::null_denotation_path (
12083 AST::PathInExpression path, AST::AttrVec outer_attrs,
12084 ParseRestrictions restrictions)
12085{
12086 rust_debug ("parsing null denotation after path");
12087
12088 // HACK: always make "self" by itself a path (regardless of next
12089 // tokens)
12090 if (path.is_single_segment () && path.get_segments ()[0].is_lower_self_seg ())
12091 {
12092 // HACK: add outer attrs to path
12093 path.set_outer_attrs (std::move (outer_attrs));
12094 return std::unique_ptr<AST::PathInExpression> (
12095 new AST::PathInExpression (std::move (path)));
12096 }
12097
12098 // branch on next token
12099 const_TokenPtr t = lexer.peek_token ();
12100 switch (t->get_id ())
12101 {
12102 case EXCLAM:
12103 // macro
12104 return parse_macro_invocation_partial (std::move (path),
12105 std::move (outer_attrs));
12106 case LEFT_CURLY: {
12107 bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER
12108 && (lexer.peek_token (2)->get_id () == COMMA
12109 || (lexer.peek_token (2)->get_id () == COLON
12110 && (lexer.peek_token (4)->get_id () == COMMA
12111 || !can_tok_start_type (
12112 lexer.peek_token (3)->get_id ()))));
12113
12114 /* definitely not a block:
12115 * path '{' ident ','
12116 * path '{' ident ':' [anything] ','
12117 * path '{' ident ':' [not a type]
12118 * otherwise, assume block expr and thus path */
12119 // DEBUG
12120 rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ",
12121 lexer.peek_token (1)->get_token_description (),
12122 lexer.peek_token (2)->get_token_description (),
12123 lexer.peek_token (3)->get_token_description (),
12124 lexer.peek_token (4)->get_token_description ());
12125
12126 rust_debug ("can be struct expr: '%s', not a block: '%s'",
12127 restrictions.can_be_struct_expr ? "true" : "false",
12128 not_a_block ? "true" : "false");
12129
12130 // struct/enum expr struct
12131 if (!restrictions.can_be_struct_expr && !not_a_block)
32c8fb0e 12132 {
32c8fb0e
JP
12133 // HACK: add outer attrs to path
12134 path.set_outer_attrs (std::move (outer_attrs));
12135 return std::unique_ptr<AST::PathInExpression> (
12136 new AST::PathInExpression (std::move (path)));
12137 }
8bc4ce7c
MJ
12138 return parse_struct_expr_struct_partial (std::move (path),
12139 std::move (outer_attrs));
32c8fb0e 12140 }
8bc4ce7c
MJ
12141 case LEFT_PAREN:
12142 // struct/enum expr tuple
12143 if (!restrictions.can_be_struct_expr)
12144 {
12145 // assume path is returned
12146 // HACK: add outer attributes to path
12147 path.set_outer_attrs (std::move (outer_attrs));
12148 return std::unique_ptr<AST::PathInExpression> (
12149 new AST::PathInExpression (std::move (path)));
12150 }
12151 return parse_struct_expr_tuple_partial (std::move (path),
12152 std::move (outer_attrs));
12153 default:
12154 // assume path is returned if not single segment
12155 if (path.is_single_segment ())
12156 {
12157 // FIXME: This should probably be returned as a path.
12158 /* HACK: may have to become permanent, but this is my current
12159 * identifier expression */
12160 return std::unique_ptr<AST::IdentifierExpr> (new AST::IdentifierExpr (
12161 path.get_segments ()[0].get_ident_segment ().as_string (), {},
12162 path.get_locus ()));
12163 }
12164 // HACK: add outer attrs to path
12165 path.set_outer_attrs (std::move (outer_attrs));
12166 return std::unique_ptr<AST::PathInExpression> (
12167 new AST::PathInExpression (std::move (path)));
12168 }
93866b6a 12169 rust_unreachable ();
8bc4ce7c
MJ
12170}
12171
12172// Handling of expresions that do not start with a path for `null_denotation`.
12173template <typename ManagedTokenSource>
12174std::unique_ptr<AST::Expr>
12175Parser<ManagedTokenSource>::null_denotation_not_path (
12176 const_TokenPtr tok, AST::AttrVec outer_attrs, ParseRestrictions restrictions)
12177{
12178 switch (tok->get_id ())
12179 {
12180 // FIXME: Handle in null_denotation_path?
2a094010 12181 case LEFT_SHIFT:
32c8fb0e
JP
12182 case LEFT_ANGLE: {
12183 // qualified path
12184 // HACK: add outer attrs to path
12185 AST::QualifiedPathInExpression path
12186 = parse_qualified_path_in_expression (tok->get_locus ());
12187 path.set_outer_attrs (std::move (outer_attrs));
12188 return std::unique_ptr<AST::QualifiedPathInExpression> (
12189 new AST::QualifiedPathInExpression (std::move (path)));
12190 }
8bc4ce7c
MJ
12191 // FIXME: delegate to parse_literal_expr instead? would have to rejig
12192 // tokens and whatever.
12193 // FIXME: for literal exprs, outer attrs should be passed in, and later
12194 // error if it does not make up the entire statement.
32c8fb0e
JP
12195 case INT_LITERAL:
12196 // we should check the range, but ignore for now
12197 // encode as int?
12198 return std::unique_ptr<AST::LiteralExpr> (
12199 new AST::LiteralExpr (tok->get_str (), AST::Literal::INT,
12200 tok->get_type_hint (), {}, tok->get_locus ()));
12201 case FLOAT_LITERAL:
12202 // encode as float?
12203 return std::unique_ptr<AST::LiteralExpr> (
12204 new AST::LiteralExpr (tok->get_str (), AST::Literal::FLOAT,
12205 tok->get_type_hint (), {}, tok->get_locus ()));
12206 case STRING_LITERAL:
12207 return std::unique_ptr<AST::LiteralExpr> (
12208 new AST::LiteralExpr (tok->get_str (), AST::Literal::STRING,
12209 tok->get_type_hint (), {}, tok->get_locus ()));
12210 case BYTE_STRING_LITERAL:
12211 return std::unique_ptr<AST::LiteralExpr> (
12212 new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE_STRING,
12213 tok->get_type_hint (), {}, tok->get_locus ()));
908a4f88 12214 case RAW_STRING_LITERAL:
12215 return std::unique_ptr<AST::LiteralExpr> (
12216 new AST::LiteralExpr (tok->get_str (), AST::Literal::RAW_STRING,
12217 tok->get_type_hint (), {}, tok->get_locus ()));
32c8fb0e
JP
12218 case CHAR_LITERAL:
12219 return std::unique_ptr<AST::LiteralExpr> (
12220 new AST::LiteralExpr (tok->get_str (), AST::Literal::CHAR,
12221 tok->get_type_hint (), {}, tok->get_locus ()));
12222 case BYTE_CHAR_LITERAL:
12223 return std::unique_ptr<AST::LiteralExpr> (
12224 new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE,
12225 tok->get_type_hint (), {}, tok->get_locus ()));
12226 case TRUE_LITERAL:
12227 return std::unique_ptr<AST::LiteralExpr> (
f1c7ce7e
PEP
12228 new AST::LiteralExpr (Values::Keywords::TRUE_LITERAL,
12229 AST::Literal::BOOL, tok->get_type_hint (), {},
12230 tok->get_locus ()));
32c8fb0e
JP
12231 case FALSE_LITERAL:
12232 return std::unique_ptr<AST::LiteralExpr> (
f1c7ce7e
PEP
12233 new AST::LiteralExpr (Values::Keywords::FALSE_LITERAL,
12234 AST::Literal::BOOL, tok->get_type_hint (), {},
12235 tok->get_locus ()));
32c8fb0e
JP
12236 case LEFT_PAREN:
12237 return parse_grouped_or_tuple_expr (std::move (outer_attrs),
12238 tok->get_locus ());
12239
12240 /*case PLUS: { // unary plus operator
12241 // invoke parse_expr recursively with appropriate priority, etc. for
12242 below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS);
12243
12244 if (expr == nullptr)
12245 return nullptr;
12246 // can only apply to integer and float expressions
12247 if (expr->get_type() != integer_type_node || expr->get_type() !=
12248 float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
12249 plus must be int or float but it is %s", print_type(expr->get_type()));
12250 return nullptr;
12251 }
12252
12253 return Tree(expr, tok->get_locus());
12254 }*/
12255 // Rust has no unary plus operator
12256 case MINUS: { // unary minus
12257 ParseRestrictions entered_from_unary;
12258 entered_from_unary.entered_from_unary = true;
12259 if (!restrictions.can_be_struct_expr)
12260 entered_from_unary.can_be_struct_expr = false;
12261 std::unique_ptr<AST::Expr> expr
12262 = parse_expr (LBP_UNARY_MINUS, {}, entered_from_unary);
12263
12264 if (expr == nullptr)
12265 return nullptr;
12266 // can only apply to integer and float expressions
12267 /*if (expr.get_type() != integer_type_node || expr.get_type() !=
12268 float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
12269 minus must be int or float but it is %s",
12270 print_type(expr.get_type())); return Tree::error();
12271 }*/
12272 /* FIXME: when implemented the "get type" method on expr, ensure it is
12273 * int or float type (except unsigned int). Actually, this would
12274 * probably have to be done in semantic analysis (as type checking).
12275 */
12276
12277 /* FIXME: allow outer attributes on these expressions by having an
12278 * outer attrs parameter in function*/
12279 return std::unique_ptr<AST::NegationExpr> (
12280 new AST::NegationExpr (std::move (expr), NegationOperator::NEGATE,
12281 std::move (outer_attrs), tok->get_locus ()));
12282 }
12283 case EXCLAM: { // logical or bitwise not
12284 ParseRestrictions entered_from_unary;
12285 entered_from_unary.entered_from_unary = true;
12286 if (!restrictions.can_be_struct_expr)
12287 entered_from_unary.can_be_struct_expr = false;
12288 std::unique_ptr<AST::Expr> expr
12289 = parse_expr (LBP_UNARY_EXCLAM, {}, entered_from_unary);
12290
12291 if (expr == nullptr)
12292 return nullptr;
12293 // can only apply to boolean expressions
12294 /*if (expr.get_type() != boolean_type_node) {
12295 rust_error_at(tok->get_locus(),
12296 "operand of logical not must be a boolean but it is %s",
12297 print_type(expr.get_type()));
12298 return Tree::error();
12299 }*/
12300 /* FIXME: type checking for boolean or integer expressions in semantic
12301 * analysis */
12302
12303 // FIXME: allow outer attributes on these expressions
12304 return std::unique_ptr<AST::NegationExpr> (
12305 new AST::NegationExpr (std::move (expr), NegationOperator::NOT,
12306 std::move (outer_attrs), tok->get_locus ()));
12307 }
12308 case ASTERISK: {
12309 /* pointer dereference only - HACK: as struct expressions should
12310 * always be value expressions, cannot be dereferenced */
12311 ParseRestrictions entered_from_unary;
12312 entered_from_unary.entered_from_unary = true;
12313 entered_from_unary.can_be_struct_expr = false;
12314 std::unique_ptr<AST::Expr> expr
12315 = parse_expr (LBP_UNARY_ASTERISK, {}, entered_from_unary);
12316 // FIXME: allow outer attributes on expression
12317 return std::unique_ptr<AST::DereferenceExpr> (
12318 new AST::DereferenceExpr (std::move (expr), std::move (outer_attrs),
12319 tok->get_locus ()));
12320 }
12321 case AMP: {
12322 // (single) "borrow" expression - shared (mutable) or immutable
12323 std::unique_ptr<AST::Expr> expr = nullptr;
a0f4c30e
PEP
12324 Mutability mutability = Mutability::Imm;
12325 bool raw_borrow = false;
32c8fb0e 12326
32c8fb0e
JP
12327 ParseRestrictions entered_from_unary;
12328 entered_from_unary.entered_from_unary = true;
b436709f
OA
12329 if (!restrictions.can_be_struct_expr)
12330 entered_from_unary.can_be_struct_expr = false;
32c8fb0e 12331
a0f4c30e
PEP
12332 auto is_mutability = [] (const_TokenPtr token) {
12333 return token->get_id () == CONST || token->get_id () == MUT;
12334 };
12335
12336 auto t = lexer.peek_token ();
12337 // Weak raw keyword, we look (1) ahead and treat it as an identifier if
12338 // there is no mut nor const.
12339 if (t->get_id () == IDENTIFIER
12340 && t->get_str () == Values::WeakKeywords::RAW
12341 && is_mutability (lexer.peek_token (1)))
12342 {
12343 lexer.skip_token ();
12344 switch (lexer.peek_token ()->get_id ())
12345 {
12346 case MUT:
12347 mutability = Mutability::Mut;
12348 break;
12349 case CONST:
12350 mutability = Mutability::Imm;
12351 break;
12352 default:
12353 rust_error_at (lexer.peek_token ()->get_locus (),
12354 "raw borrow should be either const or mut");
12355 }
12356 lexer.skip_token ();
12357 expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
12358 raw_borrow = true;
12359 }
12360 else if (t->get_id () == MUT)
32c8fb0e
JP
12361 {
12362 lexer.skip_token ();
12363 expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
a0f4c30e
PEP
12364 mutability = Mutability::Mut;
12365 raw_borrow = false;
32c8fb0e
JP
12366 }
12367 else
12368 {
12369 expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
a0f4c30e 12370 raw_borrow = false;
32c8fb0e
JP
12371 }
12372
12373 // FIXME: allow outer attributes on expression
12374 return std::unique_ptr<AST::BorrowExpr> (
a0f4c30e 12375 new AST::BorrowExpr (std::move (expr), mutability, raw_borrow, false,
32c8fb0e
JP
12376 std::move (outer_attrs), tok->get_locus ()));
12377 }
12378 case LOGICAL_AND: {
12379 // (double) "borrow" expression - shared (mutable) or immutable
12380 std::unique_ptr<AST::Expr> expr = nullptr;
a0f4c30e 12381 Mutability mutability = Mutability::Imm;
32c8fb0e
JP
12382
12383 ParseRestrictions entered_from_unary;
12384 entered_from_unary.entered_from_unary = true;
12385
12386 if (lexer.peek_token ()->get_id () == MUT)
12387 {
12388 lexer.skip_token ();
12389 expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
a0f4c30e 12390 mutability = Mutability::Mut;
32c8fb0e
JP
12391 }
12392 else
12393 {
12394 expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
a0f4c30e 12395 mutability = Mutability::Imm;
32c8fb0e
JP
12396 }
12397
12398 // FIXME: allow outer attributes on expression
12399 return std::unique_ptr<AST::BorrowExpr> (
a0f4c30e 12400 new AST::BorrowExpr (std::move (expr), mutability, false, true,
32c8fb0e
JP
12401 std::move (outer_attrs), tok->get_locus ()));
12402 }
32c8fb0e
JP
12403 case OR:
12404 case PIPE:
12405 case MOVE:
12406 // closure expression
12407 return parse_closure_expr_pratt (tok, std::move (outer_attrs));
12408 case DOT_DOT:
12409 // either "range to" or "range full" expressions
12410 return parse_nud_range_exclusive_expr (tok, std::move (outer_attrs));
12411 case DOT_DOT_EQ:
12412 // range to inclusive expr
12413 return parse_range_to_inclusive_expr (tok, std::move (outer_attrs));
7f631967 12414 case RETURN_KW:
32c8fb0e
JP
12415 // FIXME: is this really a null denotation expression?
12416 return parse_return_expr (std::move (outer_attrs), tok->get_locus ());
12417 case BREAK:
12418 // FIXME: is this really a null denotation expression?
12419 return parse_break_expr (std::move (outer_attrs), tok->get_locus ());
12420 case CONTINUE:
12421 return parse_continue_expr (std::move (outer_attrs), tok->get_locus ());
12422 case LEFT_CURLY:
12423 // ok - this is an expression with block for once.
ff04ba26
PEP
12424 return parse_block_expr (std::move (outer_attrs), tl::nullopt,
12425 tok->get_locus ());
32c8fb0e
JP
12426 case IF:
12427 // if or if let, so more lookahead to find out
d34922c4 12428 if (lexer.peek_token ()->get_id () == LET)
32c8fb0e
JP
12429 {
12430 // if let expr
12431 return parse_if_let_expr (std::move (outer_attrs), tok->get_locus ());
12432 }
12433 else
12434 {
12435 // if expr
12436 return parse_if_expr (std::move (outer_attrs), tok->get_locus ());
12437 }
48408712
MJ
12438 case LIFETIME:
12439 return parse_labelled_loop_expr (tok, std::move (outer_attrs));
32c8fb0e 12440 case LOOP:
ff04ba26 12441 return parse_loop_expr (std::move (outer_attrs), tl::nullopt,
32c8fb0e
JP
12442 tok->get_locus ());
12443 case WHILE:
e6ff2bcc
PEP
12444 if (lexer.peek_token ()->get_id () == LET)
12445 {
12446 return parse_while_let_loop_expr (std::move (outer_attrs));
12447 }
12448 else
12449 {
ff04ba26 12450 return parse_while_loop_expr (std::move (outer_attrs), tl::nullopt,
e6ff2bcc
PEP
12451 tok->get_locus ());
12452 }
48408712 12453 case FOR:
ff04ba26 12454 return parse_for_loop_expr (std::move (outer_attrs), tl::nullopt);
7f631967 12455 case MATCH_KW:
32c8fb0e
JP
12456 // also an expression with block
12457 return parse_match_expr (std::move (outer_attrs), tok->get_locus ());
12458 case LEFT_SQUARE:
12459 // array definition expr (not indexing)
12460 return parse_array_expr (std::move (outer_attrs), tok->get_locus ());
12461 case UNSAFE:
12462 return parse_unsafe_block_expr (std::move (outer_attrs),
12463 tok->get_locus ());
813a1e61
PEP
12464 case BOX:
12465 return parse_box_expr (std::move (outer_attrs), tok->get_locus ());
760f529d
AR
12466 case UNDERSCORE:
12467 add_error (
12468 Error (tok->get_locus (),
12469 "use of %qs is not allowed on the right-side of an assignment",
12470 tok->get_token_description ()));
12471 return nullptr;
32c8fb0e
JP
12472 default:
12473 if (!restrictions.expr_can_be_null)
12474 add_error (Error (tok->get_locus (),
12475 "found unexpected token %qs in null denotation",
12476 tok->get_token_description ()));
12477 return nullptr;
12478 }
12479}
12480
12481/* Called for each token that can appear in infix (between) position. Can be
12482 * operators or other punctuation. Returns a function pointer to member
12483 * function that implements the left denotation for the token given. */
12484template <typename ManagedTokenSource>
12485std::unique_ptr<AST::Expr>
12486Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok,
12487 std::unique_ptr<AST::Expr> left,
12488 AST::AttrVec outer_attrs,
12489 ParseRestrictions restrictions)
12490{
12491 // Token passed in has already been skipped, so peek gives "next" token
12492 switch (tok->get_id ())
12493 {
12494 // FIXME: allow for outer attributes to be applied
12495 case QUESTION_MARK: {
80c68893 12496 location_t left_locus = left->get_locus ();
32c8fb0e
JP
12497 // error propagation expression - unary postfix
12498 return std::unique_ptr<AST::ErrorPropagationExpr> (
12499 new AST::ErrorPropagationExpr (std::move (left),
12500 std::move (outer_attrs), left_locus));
12501 }
12502 case PLUS:
12503 // sum expression - binary infix
12504 /*return parse_binary_plus_expr (tok, std::move (left),
12505 std::move (outer_attrs), restrictions);*/
12506 return parse_arithmetic_or_logical_expr (tok, std::move (left),
12507 std::move (outer_attrs),
12508 ArithmeticOrLogicalOperator::ADD,
12509 restrictions);
12510 case MINUS:
12511 // difference expression - binary infix
12512 /*return parse_binary_minus_expr (tok, std::move (left),
12513 std::move (outer_attrs),
12514 restrictions);*/
12515 return parse_arithmetic_or_logical_expr (
12516 tok, std::move (left), std::move (outer_attrs),
12517 ArithmeticOrLogicalOperator::SUBTRACT, restrictions);
12518 case ASTERISK:
12519 // product expression - binary infix
12520 /*return parse_binary_mult_expr (tok, std::move (left),
12521 std::move (outer_attrs), restrictions);*/
12522 return parse_arithmetic_or_logical_expr (
12523 tok, std::move (left), std::move (outer_attrs),
12524 ArithmeticOrLogicalOperator::MULTIPLY, restrictions);
12525 case DIV:
12526 // quotient expression - binary infix
12527 /*return parse_binary_div_expr (tok, std::move (left),
12528 std::move (outer_attrs), restrictions);*/
12529 return parse_arithmetic_or_logical_expr (
12530 tok, std::move (left), std::move (outer_attrs),
12531 ArithmeticOrLogicalOperator::DIVIDE, restrictions);
12532 case PERCENT:
12533 // modulo expression - binary infix
12534 /*return parse_binary_mod_expr (tok, std::move (left),
12535 std::move (outer_attrs), restrictions);*/
12536 return parse_arithmetic_or_logical_expr (
12537 tok, std::move (left), std::move (outer_attrs),
12538 ArithmeticOrLogicalOperator::MODULUS, restrictions);
12539 case AMP:
12540 // logical or bitwise and expression - binary infix
12541 /*return parse_bitwise_and_expr (tok, std::move (left),
12542 std::move (outer_attrs), restrictions);*/
12543 return parse_arithmetic_or_logical_expr (
12544 tok, std::move (left), std::move (outer_attrs),
12545 ArithmeticOrLogicalOperator::BITWISE_AND, restrictions);
12546 case PIPE:
12547 // logical or bitwise or expression - binary infix
12548 /*return parse_bitwise_or_expr (tok, std::move (left),
12549 std::move (outer_attrs), restrictions);*/
12550 return parse_arithmetic_or_logical_expr (
12551 tok, std::move (left), std::move (outer_attrs),
12552 ArithmeticOrLogicalOperator::BITWISE_OR, restrictions);
12553 case CARET:
12554 // logical or bitwise xor expression - binary infix
12555 /*return parse_bitwise_xor_expr (tok, std::move (left),
12556 std::move (outer_attrs), restrictions);*/
12557 return parse_arithmetic_or_logical_expr (
12558 tok, std::move (left), std::move (outer_attrs),
12559 ArithmeticOrLogicalOperator::BITWISE_XOR, restrictions);
12560 case LEFT_SHIFT:
12561 // left shift expression - binary infix
12562 /*return parse_left_shift_expr (tok, std::move (left),
12563 std::move (outer_attrs), restrictions);*/
12564 return parse_arithmetic_or_logical_expr (
12565 tok, std::move (left), std::move (outer_attrs),
12566 ArithmeticOrLogicalOperator::LEFT_SHIFT, restrictions);
12567 case RIGHT_SHIFT:
12568 // right shift expression - binary infix
12569 /*return parse_right_shift_expr (tok, std::move (left),
12570 std::move (outer_attrs), restrictions);*/
12571 return parse_arithmetic_or_logical_expr (
12572 tok, std::move (left), std::move (outer_attrs),
12573 ArithmeticOrLogicalOperator::RIGHT_SHIFT, restrictions);
12574 case EQUAL_EQUAL:
12575 // equal to expression - binary infix (no associativity)
12576 /*return parse_binary_equal_expr (tok, std::move (left),
12577 std::move (outer_attrs),
12578 restrictions);*/
12579 return parse_comparison_expr (tok, std::move (left),
12580 std::move (outer_attrs),
12581 ComparisonOperator::EQUAL, restrictions);
12582 case NOT_EQUAL:
12583 // not equal to expression - binary infix (no associativity)
12584 /*return parse_binary_not_equal_expr (tok, std::move (left),
12585 std::move (outer_attrs),
12586 restrictions);*/
12587 return parse_comparison_expr (tok, std::move (left),
12588 std::move (outer_attrs),
12589 ComparisonOperator::NOT_EQUAL,
12590 restrictions);
12591 case RIGHT_ANGLE:
12592 // greater than expression - binary infix (no associativity)
12593 /*return parse_binary_greater_than_expr (tok, std::move (left),
12594 std::move (outer_attrs),
12595 restrictions);*/
12596 return parse_comparison_expr (tok, std::move (left),
12597 std::move (outer_attrs),
12598 ComparisonOperator::GREATER_THAN,
12599 restrictions);
12600 case LEFT_ANGLE:
12601 // less than expression - binary infix (no associativity)
12602 /*return parse_binary_less_than_expr (tok, std::move (left),
12603 std::move (outer_attrs),
12604 restrictions);*/
12605 return parse_comparison_expr (tok, std::move (left),
12606 std::move (outer_attrs),
12607 ComparisonOperator::LESS_THAN,
12608 restrictions);
12609 case GREATER_OR_EQUAL:
12610 // greater than or equal to expression - binary infix (no associativity)
12611 /*return parse_binary_greater_equal_expr (tok, std::move (left),
12612 std::move (outer_attrs),
12613 restrictions);*/
12614 return parse_comparison_expr (tok, std::move (left),
12615 std::move (outer_attrs),
12616 ComparisonOperator::GREATER_OR_EQUAL,
12617 restrictions);
12618 case LESS_OR_EQUAL:
12619 // less than or equal to expression - binary infix (no associativity)
12620 /*return parse_binary_less_equal_expr (tok, std::move (left),
12621 std::move (outer_attrs),
12622 restrictions);*/
12623 return parse_comparison_expr (tok, std::move (left),
12624 std::move (outer_attrs),
12625 ComparisonOperator::LESS_OR_EQUAL,
12626 restrictions);
12627 case OR:
12628 // lazy logical or expression - binary infix
12629 return parse_lazy_or_expr (tok, std::move (left), std::move (outer_attrs),
12630 restrictions);
12631 case LOGICAL_AND:
12632 // lazy logical and expression - binary infix
12633 return parse_lazy_and_expr (tok, std::move (left),
12634 std::move (outer_attrs), restrictions);
12635 case AS:
12636 /* type cast expression - kind of binary infix (RHS is actually a
12637 * TypeNoBounds) */
12638 return parse_type_cast_expr (tok, std::move (left),
12639 std::move (outer_attrs), restrictions);
12640 case EQUAL:
12641 // assignment expression - binary infix (note right-to-left
12642 // associativity)
12643 return parse_assig_expr (tok, std::move (left), std::move (outer_attrs),
12644 restrictions);
12645 case PLUS_EQ:
12646 /* plus-assignment expression - binary infix (note right-to-left
12647 * associativity) */
12648 /*return parse_plus_assig_expr (tok, std::move (left),
12649 std::move (outer_attrs), restrictions);*/
12650 return parse_compound_assignment_expr (tok, std::move (left),
12651 std::move (outer_attrs),
12652 CompoundAssignmentOperator::ADD,
12653 restrictions);
12654 case MINUS_EQ:
12655 /* minus-assignment expression - binary infix (note right-to-left
12656 * associativity) */
12657 /*return parse_minus_assig_expr (tok, std::move (left),
12658 std::move (outer_attrs), restrictions);*/
12659 return parse_compound_assignment_expr (
12660 tok, std::move (left), std::move (outer_attrs),
12661 CompoundAssignmentOperator::SUBTRACT, restrictions);
12662 case ASTERISK_EQ:
12663 /* multiply-assignment expression - binary infix (note right-to-left
12664 * associativity) */
12665 /*return parse_mult_assig_expr (tok, std::move (left),
12666 std::move (outer_attrs), restrictions);*/
12667 return parse_compound_assignment_expr (
12668 tok, std::move (left), std::move (outer_attrs),
12669 CompoundAssignmentOperator::MULTIPLY, restrictions);
12670 case DIV_EQ:
12671 /* division-assignment expression - binary infix (note right-to-left
12672 * associativity) */
12673 /*return parse_div_assig_expr (tok, std::move (left),
12674 std::move (outer_attrs), restrictions);*/
12675 return parse_compound_assignment_expr (tok, std::move (left),
12676 std::move (outer_attrs),
12677 CompoundAssignmentOperator::DIVIDE,
12678 restrictions);
12679 case PERCENT_EQ:
12680 /* modulo-assignment expression - binary infix (note right-to-left
12681 * associativity) */
12682 /*return parse_mod_assig_expr (tok, std::move (left),
12683 std::move (outer_attrs), restrictions);*/
12684 return parse_compound_assignment_expr (
12685 tok, std::move (left), std::move (outer_attrs),
12686 CompoundAssignmentOperator::MODULUS, restrictions);
12687 case AMP_EQ:
12688 /* bitwise and-assignment expression - binary infix (note right-to-left
12689 * associativity) */
12690 /*return parse_and_assig_expr (tok, std::move (left),
12691 std::move (outer_attrs), restrictions);*/
12692 return parse_compound_assignment_expr (
12693 tok, std::move (left), std::move (outer_attrs),
12694 CompoundAssignmentOperator::BITWISE_AND, restrictions);
12695 case PIPE_EQ:
12696 /* bitwise or-assignment expression - binary infix (note right-to-left
12697 * associativity) */
12698 /*return parse_or_assig_expr (tok, std::move (left),
12699 std::move (outer_attrs), restrictions);*/
12700 return parse_compound_assignment_expr (
12701 tok, std::move (left), std::move (outer_attrs),
12702 CompoundAssignmentOperator::BITWISE_OR, restrictions);
12703 case CARET_EQ:
12704 /* bitwise xor-assignment expression - binary infix (note right-to-left
12705 * associativity) */
12706 /*return parse_xor_assig_expr (tok, std::move (left),
12707 std::move (outer_attrs), restrictions);*/
12708 return parse_compound_assignment_expr (
12709 tok, std::move (left), std::move (outer_attrs),
12710 CompoundAssignmentOperator::BITWISE_XOR, restrictions);
12711 case LEFT_SHIFT_EQ:
12712 /* left shift-assignment expression - binary infix (note right-to-left
12713 * associativity) */
12714 /*return parse_left_shift_assig_expr (tok, std::move (left),
12715 std::move (outer_attrs),
12716 restrictions);*/
12717 return parse_compound_assignment_expr (
12718 tok, std::move (left), std::move (outer_attrs),
12719 CompoundAssignmentOperator::LEFT_SHIFT, restrictions);
12720 case RIGHT_SHIFT_EQ:
12721 /* right shift-assignment expression - binary infix (note right-to-left
12722 * associativity) */
12723 /*return parse_right_shift_assig_expr (tok, std::move (left),
12724 std::move (outer_attrs),
12725 restrictions);*/
12726 return parse_compound_assignment_expr (
12727 tok, std::move (left), std::move (outer_attrs),
12728 CompoundAssignmentOperator::RIGHT_SHIFT, restrictions);
12729 case DOT_DOT:
12730 /* range exclusive expression - binary infix (no associativity)
12731 * either "range" or "range from" */
12732 return parse_led_range_exclusive_expr (tok, std::move (left),
12733 std::move (outer_attrs),
12734 restrictions);
12735 case DOT_DOT_EQ:
12736 /* range inclusive expression - binary infix (no associativity)
12737 * unambiguously RangeInclusiveExpr */
12738 return parse_range_inclusive_expr (tok, std::move (left),
12739 std::move (outer_attrs), restrictions);
12740 case SCOPE_RESOLUTION:
12741 // path expression - binary infix? FIXME should this even be parsed
12742 // here?
12743 add_error (
12744 Error (tok->get_locus (),
12745 "found scope resolution operator in left denotation "
12746 "function - this should probably be handled elsewhere"));
12747
12748 return nullptr;
12749 case DOT: {
12750 /* field expression or method call - relies on parentheses after next
12751 * identifier or await if token after is "await" (unary postfix) or
12752 * tuple index if token after is a decimal int literal */
12753
12754 const_TokenPtr next_tok = lexer.peek_token ();
12755 if (next_tok->get_id () == IDENTIFIER
f1c7ce7e 12756 && next_tok->get_str () == Values::Keywords::AWAIT)
32c8fb0e
JP
12757 {
12758 // await expression
12759 return parse_await_expr (tok, std::move (left),
12760 std::move (outer_attrs));
12761 }
12762 else if (next_tok->get_id () == INT_LITERAL)
12763 {
12764 // tuple index expression - TODO check for decimal int literal
31112115
PEP
12765 return parse_tuple_index_expr (tok, std::move (left),
12766 std::move (outer_attrs),
12767 restrictions);
12768 }
12769 else if (next_tok->get_id () == FLOAT_LITERAL)
12770 {
12771 // Lexer has misidentified a tuple index as a float literal
12772 // eg: `(x, (y, z)).1.0` -> 1.0 has been identified as a float
12773 // literal. This means we should split it into three new separate
12774 // tokens, the first tuple index, the dot and the second tuple
12775 // index.
12776 auto current_loc = next_tok->get_locus ();
12777 auto str = next_tok->get_str ();
12778 auto dot_pos = str.find (".");
12779 auto prefix = str.substr (0, dot_pos);
12780 auto suffix = str.substr (dot_pos + 1);
348f028f
PEP
12781 if (dot_pos == str.size () - 1)
12782 lexer.split_current_token (
12783 {Token::make_int (current_loc, std::move (prefix),
12784 CORETYPE_PURE_DECIMAL),
12785 Token::make (DOT, current_loc + 1)});
12786 else
12787 lexer.split_current_token (
12788 {Token::make_int (current_loc, std::move (prefix),
12789 CORETYPE_PURE_DECIMAL),
12790 Token::make (DOT, current_loc + 1),
12791 Token::make_int (current_loc + 2, std::move (suffix),
12792 CORETYPE_PURE_DECIMAL)});
32c8fb0e
JP
12793 return parse_tuple_index_expr (tok, std::move (left),
12794 std::move (outer_attrs),
12795 restrictions);
12796 }
12797 else if (next_tok->get_id () == IDENTIFIER
12798 && lexer.peek_token (1)->get_id () != LEFT_PAREN
12799 && lexer.peek_token (1)->get_id () != SCOPE_RESOLUTION)
12800 {
12801 /* field expression (or should be) - FIXME: scope resolution right
12802 * after identifier should always be method, I'm pretty sure */
12803 return parse_field_access_expr (tok, std::move (left),
12804 std::move (outer_attrs),
12805 restrictions);
12806 }
12807 else
12808 {
12809 // method call (probably)
12810 return parse_method_call_expr (tok, std::move (left),
12811 std::move (outer_attrs),
12812 restrictions);
12813 }
12814 }
12815 case LEFT_PAREN:
12816 // function call - method call is based on dot notation first
12817 return parse_function_call_expr (tok, std::move (left),
12818 std::move (outer_attrs), restrictions);
12819 case LEFT_SQUARE:
12820 // array or slice index expression (pseudo binary infix)
12821 return parse_index_expr (tok, std::move (left), std::move (outer_attrs),
12822 restrictions);
12823 case FLOAT_LITERAL:
12824 /* HACK: get around lexer mis-identifying '.0' or '.1' or whatever as a
12825 * float literal - TODO does this happen anymore? It shouldn't. */
12826 return parse_tuple_index_expr_float (tok, std::move (left),
12827 std::move (outer_attrs),
12828 restrictions);
12829 default:
12830 add_error (Error (tok->get_locus (),
12831 "found unexpected token %qs in left denotation",
12832 tok->get_token_description ()));
12833
12834 return nullptr;
12835 }
12836}
12837
12838/* Returns the left binding power for the given ArithmeticOrLogicalExpr type.
12839 * TODO make constexpr? Would that even do anything useful? */
12840inline binding_powers
12841get_lbp_for_arithmetic_or_logical_expr (
12842 AST::ArithmeticOrLogicalExpr::ExprType expr_type)
12843{
12844 switch (expr_type)
12845 {
12846 case ArithmeticOrLogicalOperator::ADD:
12847 return LBP_PLUS;
12848 case ArithmeticOrLogicalOperator::SUBTRACT:
12849 return LBP_MINUS;
12850 case ArithmeticOrLogicalOperator::MULTIPLY:
12851 return LBP_MUL;
12852 case ArithmeticOrLogicalOperator::DIVIDE:
12853 return LBP_DIV;
12854 case ArithmeticOrLogicalOperator::MODULUS:
12855 return LBP_MOD;
12856 case ArithmeticOrLogicalOperator::BITWISE_AND:
12857 return LBP_AMP;
12858 case ArithmeticOrLogicalOperator::BITWISE_OR:
12859 return LBP_PIPE;
12860 case ArithmeticOrLogicalOperator::BITWISE_XOR:
12861 return LBP_CARET;
12862 case ArithmeticOrLogicalOperator::LEFT_SHIFT:
12863 return LBP_L_SHIFT;
12864 case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
12865 return LBP_R_SHIFT;
12866 default:
12867 // WTF? should not happen, this is an error
93866b6a 12868 rust_unreachable ();
32c8fb0e
JP
12869
12870 return LBP_PLUS;
12871 }
12872}
12873
12874// Parses an arithmetic or logical expression (with Pratt parsing).
12875template <typename ManagedTokenSource>
12876std::unique_ptr<AST::ArithmeticOrLogicalExpr>
12877Parser<ManagedTokenSource>::parse_arithmetic_or_logical_expr (
12878 const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
12879 AST::ArithmeticOrLogicalExpr::ExprType expr_type,
12880 ParseRestrictions restrictions)
12881{
12882 // parse RHS (as tok has already been consumed in parse_expression)
12883 std::unique_ptr<AST::Expr> right
12884 = parse_expr (get_lbp_for_arithmetic_or_logical_expr (expr_type),
12885 AST::AttrVec (), restrictions);
12886 if (right == nullptr)
12887 return nullptr;
12888
12889 // TODO: check types. actually, do so during semantic analysis
d991a3f1 12890 location_t locus = left->get_locus ();
32c8fb0e
JP
12891
12892 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
12893 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
12894 expr_type, locus));
12895}
12896
12897// Parses a binary addition expression (with Pratt parsing).
12898template <typename ManagedTokenSource>
12899std::unique_ptr<AST::ArithmeticOrLogicalExpr>
12900Parser<ManagedTokenSource>::parse_binary_plus_expr (
12901 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
12902 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
12903{
12904 // parse RHS (as tok has already been consumed in parse_expression)
12905 std::unique_ptr<AST::Expr> right
12906 = parse_expr (LBP_PLUS, AST::AttrVec (), restrictions);
12907 if (right == nullptr)
12908 return nullptr;
12909
12910 // TODO: check types. actually, do so during semantic analysis
d991a3f1 12911 location_t locus = left->get_locus ();
32c8fb0e
JP
12912
12913 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
12914 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
12915 ArithmeticOrLogicalOperator::ADD, locus));
12916}
12917
12918// Parses a binary subtraction expression (with Pratt parsing).
12919template <typename ManagedTokenSource>
12920std::unique_ptr<AST::ArithmeticOrLogicalExpr>
12921Parser<ManagedTokenSource>::parse_binary_minus_expr (
12922 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
12923 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
12924{
12925 // parse RHS (as tok has already been consumed in parse_expression)
12926 std::unique_ptr<AST::Expr> right
12927 = parse_expr (LBP_MINUS, AST::AttrVec (), restrictions);
12928 if (right == nullptr)
12929 return nullptr;
12930
12931 // TODO: check types. actually, do so during semantic analysis
d991a3f1 12932 location_t locus = left->get_locus ();
32c8fb0e
JP
12933
12934 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
12935 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
12936 ArithmeticOrLogicalOperator::SUBTRACT,
12937 locus));
12938}
12939
12940// Parses a binary multiplication expression (with Pratt parsing).
12941template <typename ManagedTokenSource>
12942std::unique_ptr<AST::ArithmeticOrLogicalExpr>
12943Parser<ManagedTokenSource>::parse_binary_mult_expr (
12944 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
12945 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
12946{
12947 // parse RHS (as tok has already been consumed in parse_expression)
12948 std::unique_ptr<AST::Expr> right
12949 = parse_expr (LBP_MUL, AST::AttrVec (), restrictions);
12950 if (right == nullptr)
12951 return nullptr;
12952
12953 // TODO: check types. actually, do so during semantic analysis
d991a3f1 12954 location_t locus = left->get_locus ();
32c8fb0e
JP
12955
12956 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
12957 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
12958 ArithmeticOrLogicalOperator::MULTIPLY,
12959 locus));
12960}
12961
12962// Parses a binary division expression (with Pratt parsing).
12963template <typename ManagedTokenSource>
12964std::unique_ptr<AST::ArithmeticOrLogicalExpr>
12965Parser<ManagedTokenSource>::parse_binary_div_expr (
12966 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
12967 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
12968{
12969 // parse RHS (as tok has already been consumed in parse_expression)
12970 std::unique_ptr<AST::Expr> right
12971 = parse_expr (LBP_DIV, AST::AttrVec (), restrictions);
12972 if (right == nullptr)
12973 return nullptr;
12974
12975 // TODO: check types. actually, do so during semantic analysis
d991a3f1 12976 location_t locus = left->get_locus ();
32c8fb0e
JP
12977
12978 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
12979 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
12980 ArithmeticOrLogicalOperator::DIVIDE,
12981 locus));
12982}
12983
12984// Parses a binary modulo expression (with Pratt parsing).
12985template <typename ManagedTokenSource>
12986std::unique_ptr<AST::ArithmeticOrLogicalExpr>
12987Parser<ManagedTokenSource>::parse_binary_mod_expr (
12988 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
12989 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
12990{
12991 // parse RHS (as tok has already been consumed in parse_expression)
12992 std::unique_ptr<AST::Expr> right
12993 = parse_expr (LBP_MOD, AST::AttrVec (), restrictions);
12994 if (right == nullptr)
12995 return nullptr;
12996
12997 // TODO: check types. actually, do so during semantic analysis
d991a3f1 12998 location_t locus = left->get_locus ();
32c8fb0e
JP
12999
13000 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13001 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13002 ArithmeticOrLogicalOperator::MODULUS,
13003 locus));
13004}
13005
13006/* Parses a binary bitwise (or eager logical) and expression (with Pratt
13007 * parsing). */
13008template <typename ManagedTokenSource>
13009std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13010Parser<ManagedTokenSource>::parse_bitwise_and_expr (
13011 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13012 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13013{
13014 // parse RHS (as tok has already been consumed in parse_expression)
13015 std::unique_ptr<AST::Expr> right
13016 = parse_expr (LBP_AMP, AST::AttrVec (), restrictions);
13017 if (right == nullptr)
13018 return nullptr;
13019
13020 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13021 location_t locus = left->get_locus ();
32c8fb0e
JP
13022
13023 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13024 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13025 ArithmeticOrLogicalOperator::BITWISE_AND,
13026 locus));
13027}
13028
13029/* Parses a binary bitwise (or eager logical) or expression (with Pratt
13030 * parsing). */
13031template <typename ManagedTokenSource>
13032std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13033Parser<ManagedTokenSource>::parse_bitwise_or_expr (
13034 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13035 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13036{
13037 // parse RHS (as tok has already been consumed in parse_expression)
13038 std::unique_ptr<AST::Expr> right
13039 = parse_expr (LBP_PIPE, AST::AttrVec (), restrictions);
13040 if (right == nullptr)
13041 return nullptr;
13042
13043 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13044 location_t locus = left->get_locus ();
32c8fb0e
JP
13045
13046 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13047 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13048 ArithmeticOrLogicalOperator::BITWISE_OR,
13049 locus));
13050}
13051
13052/* Parses a binary bitwise (or eager logical) xor expression (with Pratt
13053 * parsing). */
13054template <typename ManagedTokenSource>
13055std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13056Parser<ManagedTokenSource>::parse_bitwise_xor_expr (
13057 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13058 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13059{
13060 // parse RHS (as tok has already been consumed in parse_expression)
13061 std::unique_ptr<AST::Expr> right
13062 = parse_expr (LBP_CARET, AST::AttrVec (), restrictions);
13063 if (right == nullptr)
13064 return nullptr;
13065
13066 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13067 location_t locus = left->get_locus ();
32c8fb0e
JP
13068
13069 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13070 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13071 ArithmeticOrLogicalOperator::BITWISE_XOR,
13072 locus));
13073}
13074
13075// Parses a binary left shift expression (with Pratt parsing).
13076template <typename ManagedTokenSource>
13077std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13078Parser<ManagedTokenSource>::parse_left_shift_expr (
13079 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13080 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13081{
13082 // parse RHS (as tok has already been consumed in parse_expression)
13083 std::unique_ptr<AST::Expr> right
13084 = parse_expr (LBP_L_SHIFT, AST::AttrVec (), restrictions);
13085 if (right == nullptr)
13086 return nullptr;
13087
13088 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13089 location_t locus = left->get_locus ();
32c8fb0e
JP
13090
13091 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13092 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13093 ArithmeticOrLogicalOperator::LEFT_SHIFT,
13094 locus));
13095}
13096
13097// Parses a binary right shift expression (with Pratt parsing).
13098template <typename ManagedTokenSource>
13099std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13100Parser<ManagedTokenSource>::parse_right_shift_expr (
13101 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13102 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13103{
13104 // parse RHS (as tok has already been consumed in parse_expression)
13105 std::unique_ptr<AST::Expr> right
13106 = parse_expr (LBP_R_SHIFT, AST::AttrVec (), restrictions);
13107 if (right == nullptr)
13108 return nullptr;
13109
13110 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13111 location_t locus = left->get_locus ();
32c8fb0e
JP
13112
13113 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13114 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13115 ArithmeticOrLogicalOperator::RIGHT_SHIFT,
13116 locus));
13117}
13118
13119/* Returns the left binding power for the given ComparisonExpr type.
13120 * TODO make constexpr? Would that even do anything useful? */
13121inline binding_powers
13122get_lbp_for_comparison_expr (AST::ComparisonExpr::ExprType expr_type)
13123{
13124 switch (expr_type)
13125 {
13126 case ComparisonOperator::EQUAL:
13127 return LBP_EQUAL;
13128 case ComparisonOperator::NOT_EQUAL:
13129 return LBP_NOT_EQUAL;
13130 case ComparisonOperator::GREATER_THAN:
13131 return LBP_GREATER_THAN;
13132 case ComparisonOperator::LESS_THAN:
13133 return LBP_SMALLER_THAN;
13134 case ComparisonOperator::GREATER_OR_EQUAL:
13135 return LBP_GREATER_EQUAL;
13136 case ComparisonOperator::LESS_OR_EQUAL:
13137 return LBP_SMALLER_EQUAL;
13138 default:
13139 // WTF? should not happen, this is an error
93866b6a 13140 rust_unreachable ();
32c8fb0e
JP
13141
13142 return LBP_EQUAL;
13143 }
13144}
13145
13146/* Parses a ComparisonExpr of given type and LBP. TODO find a way to only
13147 * specify one and have the other looked up - e.g. specify ExprType and
13148 * binding power is looked up? */
13149template <typename ManagedTokenSource>
13150std::unique_ptr<AST::ComparisonExpr>
13151Parser<ManagedTokenSource>::parse_comparison_expr (
13152 const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
13153 AST::ComparisonExpr::ExprType expr_type, ParseRestrictions restrictions)
13154{
13155 // parse RHS (as tok has already been consumed in parse_expression)
13156 std::unique_ptr<AST::Expr> right
13157 = parse_expr (get_lbp_for_comparison_expr (expr_type), AST::AttrVec (),
13158 restrictions);
13159 if (right == nullptr)
13160 return nullptr;
13161
13162 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13163 location_t locus = left->get_locus ();
32c8fb0e
JP
13164
13165 return std::unique_ptr<AST::ComparisonExpr> (
13166 new AST::ComparisonExpr (std::move (left), std::move (right), expr_type,
13167 locus));
13168}
13169
13170// Parses a binary equal to expression (with Pratt parsing).
13171template <typename ManagedTokenSource>
13172std::unique_ptr<AST::ComparisonExpr>
13173Parser<ManagedTokenSource>::parse_binary_equal_expr (
13174 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13175 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13176{
13177 // parse RHS (as tok has already been consumed in parse_expression)
13178 std::unique_ptr<AST::Expr> right
13179 = parse_expr (LBP_EQUAL, AST::AttrVec (), restrictions);
13180 if (right == nullptr)
13181 return nullptr;
13182
13183 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13184 location_t locus = left->get_locus ();
32c8fb0e
JP
13185
13186 return std::unique_ptr<AST::ComparisonExpr> (
13187 new AST::ComparisonExpr (std::move (left), std::move (right),
13188 ComparisonOperator::EQUAL, locus));
13189}
13190
13191// Parses a binary not equal to expression (with Pratt parsing).
13192template <typename ManagedTokenSource>
13193std::unique_ptr<AST::ComparisonExpr>
13194Parser<ManagedTokenSource>::parse_binary_not_equal_expr (
13195 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13196 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13197{
13198 // parse RHS (as tok has already been consumed in parse_expression)
13199 std::unique_ptr<AST::Expr> right
13200 = parse_expr (LBP_NOT_EQUAL, AST::AttrVec (), restrictions);
13201 if (right == nullptr)
13202 return nullptr;
13203
13204 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13205 location_t locus = left->get_locus ();
32c8fb0e
JP
13206
13207 return std::unique_ptr<AST::ComparisonExpr> (
13208 new AST::ComparisonExpr (std::move (left), std::move (right),
13209 ComparisonOperator::NOT_EQUAL, locus));
13210}
13211
13212// Parses a binary greater than expression (with Pratt parsing).
13213template <typename ManagedTokenSource>
13214std::unique_ptr<AST::ComparisonExpr>
13215Parser<ManagedTokenSource>::parse_binary_greater_than_expr (
13216 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13217 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13218{
13219 // parse RHS (as tok has already been consumed in parse_expression)
13220 std::unique_ptr<AST::Expr> right
13221 = parse_expr (LBP_GREATER_THAN, AST::AttrVec (), restrictions);
13222 if (right == nullptr)
13223 return nullptr;
13224
13225 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13226 location_t locus = left->get_locus ();
32c8fb0e
JP
13227
13228 return std::unique_ptr<AST::ComparisonExpr> (
13229 new AST::ComparisonExpr (std::move (left), std::move (right),
13230 ComparisonOperator::GREATER_THAN, locus));
13231}
13232
13233// Parses a binary less than expression (with Pratt parsing).
13234template <typename ManagedTokenSource>
13235std::unique_ptr<AST::ComparisonExpr>
13236Parser<ManagedTokenSource>::parse_binary_less_than_expr (
13237 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13238 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13239{
13240 // parse RHS (as tok has already been consumed in parse_expression)
13241 std::unique_ptr<AST::Expr> right
13242 = parse_expr (LBP_SMALLER_THAN, AST::AttrVec (), restrictions);
13243 if (right == nullptr)
13244 return nullptr;
13245
13246 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13247 location_t locus = left->get_locus ();
32c8fb0e
JP
13248
13249 return std::unique_ptr<AST::ComparisonExpr> (
13250 new AST::ComparisonExpr (std::move (left), std::move (right),
13251 ComparisonOperator::LESS_THAN, locus));
13252}
13253
13254// Parses a binary greater than or equal to expression (with Pratt parsing).
13255template <typename ManagedTokenSource>
13256std::unique_ptr<AST::ComparisonExpr>
13257Parser<ManagedTokenSource>::parse_binary_greater_equal_expr (
13258 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13259 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13260{
13261 // parse RHS (as tok has already been consumed in parse_expression)
13262 std::unique_ptr<AST::Expr> right
13263 = parse_expr (LBP_GREATER_EQUAL, AST::AttrVec (), restrictions);
13264 if (right == nullptr)
13265 return nullptr;
13266
13267 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13268 location_t locus = left->get_locus ();
32c8fb0e
JP
13269
13270 return std::unique_ptr<AST::ComparisonExpr> (
13271 new AST::ComparisonExpr (std::move (left), std::move (right),
13272 ComparisonOperator::GREATER_OR_EQUAL, locus));
13273}
13274
13275// Parses a binary less than or equal to expression (with Pratt parsing).
13276template <typename ManagedTokenSource>
13277std::unique_ptr<AST::ComparisonExpr>
13278Parser<ManagedTokenSource>::parse_binary_less_equal_expr (
13279 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13280 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13281{
13282 // parse RHS (as tok has already been consumed in parse_expression)
13283 std::unique_ptr<AST::Expr> right
13284 = parse_expr (LBP_SMALLER_EQUAL, AST::AttrVec (), restrictions);
13285 if (right == nullptr)
13286 return nullptr;
13287
13288 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13289 location_t locus = left->get_locus ();
32c8fb0e
JP
13290
13291 return std::unique_ptr<AST::ComparisonExpr> (
13292 new AST::ComparisonExpr (std::move (left), std::move (right),
13293 ComparisonOperator::LESS_OR_EQUAL, locus));
13294}
13295
13296// Parses a binary lazy boolean or expression (with Pratt parsing).
13297template <typename ManagedTokenSource>
13298std::unique_ptr<AST::LazyBooleanExpr>
13299Parser<ManagedTokenSource>::parse_lazy_or_expr (
13300 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13301 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13302{
13303 // parse RHS (as tok has already been consumed in parse_expression)
13304 std::unique_ptr<AST::Expr> right
13305 = parse_expr (LBP_LOGICAL_OR, AST::AttrVec (), restrictions);
13306 if (right == nullptr)
13307 return nullptr;
13308
13309 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13310 location_t locus = left->get_locus ();
32c8fb0e
JP
13311
13312 return std::unique_ptr<AST::LazyBooleanExpr> (
13313 new AST::LazyBooleanExpr (std::move (left), std::move (right),
13314 LazyBooleanOperator::LOGICAL_OR, locus));
13315}
13316
13317// Parses a binary lazy boolean and expression (with Pratt parsing).
13318template <typename ManagedTokenSource>
13319std::unique_ptr<AST::LazyBooleanExpr>
13320Parser<ManagedTokenSource>::parse_lazy_and_expr (
13321 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13322 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13323{
13324 // parse RHS (as tok has already been consumed in parse_expression)
13325 std::unique_ptr<AST::Expr> right
13326 = parse_expr (LBP_LOGICAL_AND, AST::AttrVec (), restrictions);
13327 if (right == nullptr)
13328 return nullptr;
13329
13330 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13331 location_t locus = left->get_locus ();
32c8fb0e
JP
13332
13333 return std::unique_ptr<AST::LazyBooleanExpr> (
13334 new AST::LazyBooleanExpr (std::move (left), std::move (right),
13335 LazyBooleanOperator::LOGICAL_AND, locus));
13336}
13337
13338// Parses a pseudo-binary infix type cast expression (with Pratt parsing).
13339template <typename ManagedTokenSource>
13340std::unique_ptr<AST::TypeCastExpr>
13341Parser<ManagedTokenSource>::parse_type_cast_expr (
13342 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> expr_to_cast,
13343 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED,
13344 ParseRestrictions restrictions ATTRIBUTE_UNUSED)
13345{
13346 // parse RHS (as tok has already been consumed in parse_expression)
13347 std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
13348 if (type == nullptr)
13349 return nullptr;
13350 // FIXME: how do I get precedence put in here?
13351
13352 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13353 location_t locus = expr_to_cast->get_locus ();
32c8fb0e
JP
13354
13355 return std::unique_ptr<AST::TypeCastExpr> (
13356 new AST::TypeCastExpr (std::move (expr_to_cast), std::move (type), locus));
13357}
13358
13359// Parses a binary assignment expression (with Pratt parsing).
13360template <typename ManagedTokenSource>
13361std::unique_ptr<AST::AssignmentExpr>
13362Parser<ManagedTokenSource>::parse_assig_expr (
13363 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13364 AST::AttrVec outer_attrs, ParseRestrictions restrictions)
13365{
13366 // parse RHS (as tok has already been consumed in parse_expression)
13367 std::unique_ptr<AST::Expr> right
13368 = parse_expr (LBP_ASSIG - 1, AST::AttrVec (), restrictions);
13369 if (right == nullptr)
13370 return nullptr;
13371 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13372
13373 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13374 location_t locus = left->get_locus ();
32c8fb0e
JP
13375
13376 return std::unique_ptr<AST::AssignmentExpr> (
13377 new AST::AssignmentExpr (std::move (left), std::move (right),
13378 std::move (outer_attrs), locus));
13379}
13380
13381/* Returns the left binding power for the given CompoundAssignmentExpr type.
13382 * TODO make constexpr? Would that even do anything useful? */
13383inline binding_powers
13384get_lbp_for_compound_assignment_expr (
13385 AST::CompoundAssignmentExpr::ExprType expr_type)
13386{
13387 switch (expr_type)
13388 {
13389 case CompoundAssignmentOperator::ADD:
13390 return LBP_PLUS;
13391 case CompoundAssignmentOperator::SUBTRACT:
13392 return LBP_MINUS;
13393 case CompoundAssignmentOperator::MULTIPLY:
13394 return LBP_MUL;
13395 case CompoundAssignmentOperator::DIVIDE:
13396 return LBP_DIV;
13397 case CompoundAssignmentOperator::MODULUS:
13398 return LBP_MOD;
13399 case CompoundAssignmentOperator::BITWISE_AND:
13400 return LBP_AMP;
13401 case CompoundAssignmentOperator::BITWISE_OR:
13402 return LBP_PIPE;
13403 case CompoundAssignmentOperator::BITWISE_XOR:
13404 return LBP_CARET;
13405 case CompoundAssignmentOperator::LEFT_SHIFT:
13406 return LBP_L_SHIFT;
13407 case CompoundAssignmentOperator::RIGHT_SHIFT:
13408 return LBP_R_SHIFT;
13409 default:
13410 // WTF? should not happen, this is an error
93866b6a 13411 rust_unreachable ();
32c8fb0e
JP
13412
13413 return LBP_PLUS;
13414 }
13415}
13416
13417// Parses a compound assignment expression (with Pratt parsing).
13418template <typename ManagedTokenSource>
13419std::unique_ptr<AST::CompoundAssignmentExpr>
13420Parser<ManagedTokenSource>::parse_compound_assignment_expr (
13421 const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
13422 AST::CompoundAssignmentExpr::ExprType expr_type,
13423 ParseRestrictions restrictions)
13424{
13425 // parse RHS (as tok has already been consumed in parse_expression)
13426 std::unique_ptr<AST::Expr> right
13427 = parse_expr (get_lbp_for_compound_assignment_expr (expr_type) - 1,
13428 AST::AttrVec (), restrictions);
13429 if (right == nullptr)
13430 return nullptr;
13431 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13432
13433 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13434 location_t locus = left->get_locus ();
32c8fb0e
JP
13435
13436 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13437 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13438 expr_type, locus));
13439}
13440
13441// Parses a binary add-assignment expression (with Pratt parsing).
13442template <typename ManagedTokenSource>
13443std::unique_ptr<AST::CompoundAssignmentExpr>
13444Parser<ManagedTokenSource>::parse_plus_assig_expr (
13445 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13446 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13447{
13448 // parse RHS (as tok has already been consumed in parse_expression)
13449 std::unique_ptr<AST::Expr> right
13450 = parse_expr (LBP_PLUS_ASSIG - 1, AST::AttrVec (), restrictions);
13451 if (right == nullptr)
13452 return nullptr;
13453 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13454
13455 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13456 location_t locus = left->get_locus ();
32c8fb0e
JP
13457
13458 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13459 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13460 CompoundAssignmentOperator::ADD, locus));
13461}
13462
13463// Parses a binary minus-assignment expression (with Pratt parsing).
13464template <typename ManagedTokenSource>
13465std::unique_ptr<AST::CompoundAssignmentExpr>
13466Parser<ManagedTokenSource>::parse_minus_assig_expr (
13467 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13468 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13469{
13470 // parse RHS (as tok has already been consumed in parse_expression)
13471 std::unique_ptr<AST::Expr> right
13472 = parse_expr (LBP_MINUS_ASSIG - 1, AST::AttrVec (), restrictions);
13473 if (right == nullptr)
13474 return nullptr;
13475 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13476
13477 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13478 location_t locus = left->get_locus ();
32c8fb0e
JP
13479
13480 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13481 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13482 CompoundAssignmentOperator::SUBTRACT,
13483 locus));
13484}
13485
13486// Parses a binary multiplication-assignment expression (with Pratt parsing).
13487template <typename ManagedTokenSource>
13488std::unique_ptr<AST::CompoundAssignmentExpr>
13489Parser<ManagedTokenSource>::parse_mult_assig_expr (
13490 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13491 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13492{
13493 // parse RHS (as tok has already been consumed in parse_expression)
13494 std::unique_ptr<AST::Expr> right
13495 = parse_expr (LBP_MULT_ASSIG - 1, AST::AttrVec (), restrictions);
13496 if (right == nullptr)
13497 return nullptr;
13498 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13499
13500 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13501 location_t locus = left->get_locus ();
32c8fb0e
JP
13502
13503 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13504 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13505 CompoundAssignmentOperator::MULTIPLY,
13506 locus));
13507}
13508
13509// Parses a binary division-assignment expression (with Pratt parsing).
13510template <typename ManagedTokenSource>
13511std::unique_ptr<AST::CompoundAssignmentExpr>
13512Parser<ManagedTokenSource>::parse_div_assig_expr (
13513 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13514 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13515{
13516 // parse RHS (as tok has already been consumed in parse_expression)
13517 std::unique_ptr<AST::Expr> right
13518 = parse_expr (LBP_DIV_ASSIG - 1, AST::AttrVec (), restrictions);
13519 if (right == nullptr)
13520 return nullptr;
13521 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13522
13523 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13524 location_t locus = left->get_locus ();
32c8fb0e
JP
13525
13526 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13527 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13528 CompoundAssignmentOperator::DIVIDE,
13529 locus));
13530}
13531
13532// Parses a binary modulo-assignment expression (with Pratt parsing).
13533template <typename ManagedTokenSource>
13534std::unique_ptr<AST::CompoundAssignmentExpr>
13535Parser<ManagedTokenSource>::parse_mod_assig_expr (
13536 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13537 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13538{
13539 // parse RHS (as tok has already been consumed in parse_expression)
13540 std::unique_ptr<AST::Expr> right
13541 = parse_expr (LBP_MOD_ASSIG - 1, AST::AttrVec (), restrictions);
13542 if (right == nullptr)
13543 return nullptr;
13544 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13545
13546 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13547 location_t locus = left->get_locus ();
32c8fb0e
JP
13548
13549 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13550 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13551 CompoundAssignmentOperator::MODULUS,
13552 locus));
13553}
13554
13555// Parses a binary and-assignment expression (with Pratt parsing).
13556template <typename ManagedTokenSource>
13557std::unique_ptr<AST::CompoundAssignmentExpr>
13558Parser<ManagedTokenSource>::parse_and_assig_expr (
13559 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13560 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13561{
13562 // parse RHS (as tok has already been consumed in parse_expression)
13563 std::unique_ptr<AST::Expr> right
13564 = parse_expr (LBP_AMP_ASSIG - 1, AST::AttrVec (), restrictions);
13565 if (right == nullptr)
13566 return nullptr;
13567 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13568
13569 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13570 location_t locus = left->get_locus ();
32c8fb0e
JP
13571
13572 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13573 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13574 CompoundAssignmentOperator::BITWISE_AND,
13575 locus));
13576}
13577
13578// Parses a binary or-assignment expression (with Pratt parsing).
13579template <typename ManagedTokenSource>
13580std::unique_ptr<AST::CompoundAssignmentExpr>
13581Parser<ManagedTokenSource>::parse_or_assig_expr (
13582 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13583 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13584{
13585 // parse RHS (as tok has already been consumed in parse_expression)
13586 std::unique_ptr<AST::Expr> right
13587 = parse_expr (LBP_PIPE_ASSIG - 1, AST::AttrVec (), restrictions);
13588 if (right == nullptr)
13589 return nullptr;
13590 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13591
13592 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13593 location_t locus = left->get_locus ();
32c8fb0e
JP
13594
13595 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13596 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13597 CompoundAssignmentOperator::BITWISE_OR,
13598 locus));
13599}
13600
13601// Parses a binary xor-assignment expression (with Pratt parsing).
13602template <typename ManagedTokenSource>
13603std::unique_ptr<AST::CompoundAssignmentExpr>
13604Parser<ManagedTokenSource>::parse_xor_assig_expr (
13605 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13606 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13607{
13608 // parse RHS (as tok has already been consumed in parse_expression)
13609 std::unique_ptr<AST::Expr> right
13610 = parse_expr (LBP_CARET_ASSIG - 1, AST::AttrVec (), restrictions);
13611 if (right == nullptr)
13612 return nullptr;
13613 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13614
13615 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13616 location_t locus = left->get_locus ();
32c8fb0e
JP
13617
13618 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13619 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13620 CompoundAssignmentOperator::BITWISE_XOR,
13621 locus));
13622}
13623
13624// Parses a binary left shift-assignment expression (with Pratt parsing).
13625template <typename ManagedTokenSource>
13626std::unique_ptr<AST::CompoundAssignmentExpr>
13627Parser<ManagedTokenSource>::parse_left_shift_assig_expr (
13628 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13629 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13630{
13631 // parse RHS (as tok has already been consumed in parse_expression)
13632 std::unique_ptr<AST::Expr> right
13633 = parse_expr (LBP_L_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
13634 if (right == nullptr)
13635 return nullptr;
13636 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13637
13638 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13639 location_t locus = left->get_locus ();
32c8fb0e
JP
13640
13641 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13642 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13643 CompoundAssignmentOperator::LEFT_SHIFT,
13644 locus));
13645}
13646
13647// Parses a binary right shift-assignment expression (with Pratt parsing).
13648template <typename ManagedTokenSource>
13649std::unique_ptr<AST::CompoundAssignmentExpr>
13650Parser<ManagedTokenSource>::parse_right_shift_assig_expr (
13651 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13652 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13653{
13654 // parse RHS (as tok has already been consumed in parse_expression)
13655 std::unique_ptr<AST::Expr> right
13656 = parse_expr (LBP_R_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
13657 if (right == nullptr)
13658 return nullptr;
13659 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13660
13661 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13662 location_t locus = left->get_locus ();
32c8fb0e
JP
13663
13664 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13665 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13666 CompoundAssignmentOperator::RIGHT_SHIFT,
13667 locus));
13668}
13669
13670// Parses a postfix unary await expression (with Pratt parsing).
13671template <typename ManagedTokenSource>
13672std::unique_ptr<AST::AwaitExpr>
13673Parser<ManagedTokenSource>::parse_await_expr (
13674 const_TokenPtr tok, std::unique_ptr<AST::Expr> expr_to_await,
13675 AST::AttrVec outer_attrs)
13676{
13677 /* skip "await" identifier (as "." has already been consumed in
13678 * parse_expression) this assumes that the identifier was already identified
13679 * as await */
13680 if (!skip_token (IDENTIFIER))
13681 {
13682 Error error (tok->get_locus (), "failed to skip %<await%> in await expr "
13683 "- this is probably a deep issue");
13684 add_error (std::move (error));
13685
13686 // skip somewhere?
13687 return nullptr;
13688 }
13689
13690 // TODO: check inside async block in semantic analysis
d991a3f1 13691 location_t locus = expr_to_await->get_locus ();
32c8fb0e
JP
13692
13693 return std::unique_ptr<AST::AwaitExpr> (
13694 new AST::AwaitExpr (std::move (expr_to_await), std::move (outer_attrs),
13695 locus));
13696}
13697
13698/* Parses an exclusive range ('..') in left denotation position (i.e.
13699 * RangeFromExpr or RangeFromToExpr). */
13700template <typename ManagedTokenSource>
13701std::unique_ptr<AST::RangeExpr>
13702Parser<ManagedTokenSource>::parse_led_range_exclusive_expr (
13703 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13704 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13705{
13706 // FIXME: this probably parses expressions accidently or whatever
13707 // try parsing RHS (as tok has already been consumed in parse_expression)
13708 // Can be nullptr, in which case it is a RangeFromExpr, otherwise a
13709 // RangeFromToExpr.
13710 restrictions.expr_can_be_null = true;
13711 std::unique_ptr<AST::Expr> right
13712 = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
13713
d991a3f1 13714 location_t locus = left->get_locus ();
32c8fb0e
JP
13715
13716 if (right == nullptr)
13717 {
13718 // range from expr
13719 return std::unique_ptr<AST::RangeFromExpr> (
13720 new AST::RangeFromExpr (std::move (left), locus));
13721 }
13722 else
13723 {
13724 return std::unique_ptr<AST::RangeFromToExpr> (
13725 new AST::RangeFromToExpr (std::move (left), std::move (right), locus));
13726 }
13727 // FIXME: make non-associative
13728}
13729
13730/* Parses an exclusive range ('..') in null denotation position (i.e.
13731 * RangeToExpr or RangeFullExpr). */
13732template <typename ManagedTokenSource>
13733std::unique_ptr<AST::RangeExpr>
13734Parser<ManagedTokenSource>::parse_nud_range_exclusive_expr (
13735 const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
13736{
f7014b28
AC
13737 auto restrictions = ParseRestrictions ();
13738 restrictions.expr_can_be_null = true;
13739
32c8fb0e
JP
13740 // FIXME: this probably parses expressions accidently or whatever
13741 // try parsing RHS (as tok has already been consumed in parse_expression)
f7014b28
AC
13742 std::unique_ptr<AST::Expr> right
13743 = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
32c8fb0e 13744
d991a3f1 13745 location_t locus = tok->get_locus ();
32c8fb0e
JP
13746
13747 if (right == nullptr)
13748 {
13749 // range from expr
13750 return std::unique_ptr<AST::RangeFullExpr> (
13751 new AST::RangeFullExpr (locus));
13752 }
13753 else
13754 {
13755 return std::unique_ptr<AST::RangeToExpr> (
13756 new AST::RangeToExpr (std::move (right), locus));
13757 }
13758 // FIXME: make non-associative
13759}
13760
13761// Parses a full binary range inclusive expression.
13762template <typename ManagedTokenSource>
13763std::unique_ptr<AST::RangeFromToInclExpr>
13764Parser<ManagedTokenSource>::parse_range_inclusive_expr (
13765 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13766 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13767{
13768 // parse RHS (as tok has already been consumed in parse_expression)
13769 std::unique_ptr<AST::Expr> right
13770 = parse_expr (LBP_DOT_DOT_EQ, AST::AttrVec (), restrictions);
13771 if (right == nullptr)
13772 return nullptr;
13773 // FIXME: make non-associative
13774
13775 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13776 location_t locus = left->get_locus ();
32c8fb0e
JP
13777
13778 return std::unique_ptr<AST::RangeFromToInclExpr> (
13779 new AST::RangeFromToInclExpr (std::move (left), std::move (right), locus));
13780}
13781
13782// Parses an inclusive range-to prefix unary expression.
13783template <typename ManagedTokenSource>
13784std::unique_ptr<AST::RangeToInclExpr>
13785Parser<ManagedTokenSource>::parse_range_to_inclusive_expr (
13786 const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
13787{
13788 // parse RHS (as tok has already been consumed in parse_expression)
13789 std::unique_ptr<AST::Expr> right = parse_expr (LBP_DOT_DOT_EQ);
13790 if (right == nullptr)
13791 return nullptr;
13792 // FIXME: make non-associative
13793
13794 // TODO: check types. actually, do so during semantic analysis
13795
13796 return std::unique_ptr<AST::RangeToInclExpr> (
13797 new AST::RangeToInclExpr (std::move (right), tok->get_locus ()));
13798}
13799
13800// Parses a pseudo-binary infix tuple index expression.
13801template <typename ManagedTokenSource>
13802std::unique_ptr<AST::TupleIndexExpr>
13803Parser<ManagedTokenSource>::parse_tuple_index_expr (
13804 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> tuple_expr,
13805 AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
13806{
13807 // parse int literal (as token already skipped)
13808 const_TokenPtr index_tok = expect_token (INT_LITERAL);
13809 if (index_tok == nullptr)
13810 {
13811 return nullptr;
13812 }
13813 std::string index = index_tok->get_str ();
13814
13815 // convert to integer
13816 if (!index_tok->is_pure_decimal ())
13817 {
13818 Error error (index_tok->get_locus (),
13819 "tuple index should be a pure decimal literal");
13820 add_error (std::move (error));
13821 }
13822 int index_int = atoi (index.c_str ());
13823
d991a3f1 13824 location_t locus = tuple_expr->get_locus ();
32c8fb0e
JP
13825
13826 return std::unique_ptr<AST::TupleIndexExpr> (
13827 new AST::TupleIndexExpr (std::move (tuple_expr), index_int,
13828 std::move (outer_attrs), locus));
13829}
13830
13831// Parses a pseudo-binary infix array (or slice) index expression.
13832template <typename ManagedTokenSource>
13833std::unique_ptr<AST::ArrayIndexExpr>
13834Parser<ManagedTokenSource>::parse_index_expr (
13835 const_TokenPtr, std::unique_ptr<AST::Expr> array_expr,
13836 AST::AttrVec outer_attrs, ParseRestrictions)
13837{
13838 // parse RHS (as tok has already been consumed in parse_expression)
13839 /*std::unique_ptr<AST::Expr> index_expr
13840 = parse_expr (LBP_ARRAY_REF, AST::AttrVec (),
13841 restrictions);*/
13842 // TODO: conceptually, should treat [] as brackets, so just parse all expr
13843 std::unique_ptr<AST::Expr> index_expr = parse_expr ();
13844 if (index_expr == nullptr)
13845 return nullptr;
13846
13847 // skip ']' at end of array
13848 if (!skip_token (RIGHT_SQUARE))
13849 {
13850 // skip somewhere?
13851 return nullptr;
13852 }
13853
13854 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13855 location_t locus = array_expr->get_locus ();
32c8fb0e
JP
13856
13857 return std::unique_ptr<AST::ArrayIndexExpr> (
13858 new AST::ArrayIndexExpr (std::move (array_expr), std::move (index_expr),
13859 std::move (outer_attrs), locus));
13860}
13861
13862// Parses a pseudo-binary infix struct field access expression.
13863template <typename ManagedTokenSource>
13864std::unique_ptr<AST::FieldAccessExpr>
13865Parser<ManagedTokenSource>::parse_field_access_expr (
13866 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> struct_expr,
13867 AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
13868{
13869 /* get field name identifier (assume that this is a field access expr and
13870 * not await, for instance) */
13871 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
13872 if (ident_tok == nullptr)
13873 return nullptr;
13874
1c3a8fbb 13875 Identifier ident{ident_tok};
32c8fb0e 13876
d991a3f1 13877 location_t locus = struct_expr->get_locus ();
32c8fb0e
JP
13878
13879 // TODO: check types. actually, do so during semantic analysis
13880 return std::unique_ptr<AST::FieldAccessExpr> (
13881 new AST::FieldAccessExpr (std::move (struct_expr), std::move (ident),
13882 std::move (outer_attrs), locus));
13883}
13884
13885// Parses a pseudo-binary infix method call expression.
13886template <typename ManagedTokenSource>
13887std::unique_ptr<AST::MethodCallExpr>
13888Parser<ManagedTokenSource>::parse_method_call_expr (
13889 const_TokenPtr tok, std::unique_ptr<AST::Expr> receiver_expr,
13890 AST::AttrVec outer_attrs, ParseRestrictions)
13891{
13892 // parse path expr segment
13893 AST::PathExprSegment segment = parse_path_expr_segment ();
13894 if (segment.is_error ())
13895 {
13896 Error error (tok->get_locus (),
13897 "failed to parse path expr segment of method call expr");
13898 add_error (std::move (error));
13899
13900 return nullptr;
13901 }
13902
13903 // skip left parentheses
13904 if (!skip_token (LEFT_PAREN))
13905 {
13906 return nullptr;
13907 }
13908
13909 // parse method params (if they exist)
13910 std::vector<std::unique_ptr<AST::Expr>> params;
13911
13912 const_TokenPtr t = lexer.peek_token ();
13913 while (t->get_id () != RIGHT_PAREN)
13914 {
13915 std::unique_ptr<AST::Expr> param = parse_expr ();
13916 if (param == nullptr)
13917 {
13918 Error error (t->get_locus (),
13919 "failed to parse method param in method call");
13920 add_error (std::move (error));
13921
13922 return nullptr;
13923 }
13924 params.push_back (std::move (param));
13925
13926 if (lexer.peek_token ()->get_id () != COMMA)
13927 break;
13928
13929 lexer.skip_token ();
13930 t = lexer.peek_token ();
13931 }
13932
13933 // skip right paren
13934 if (!skip_token (RIGHT_PAREN))
13935 {
13936 return nullptr;
13937 }
13938
13939 // TODO: check types. actually do so in semantic analysis pass.
d991a3f1 13940 location_t locus = receiver_expr->get_locus ();
32c8fb0e
JP
13941
13942 return std::unique_ptr<AST::MethodCallExpr> (
13943 new AST::MethodCallExpr (std::move (receiver_expr), std::move (segment),
13944 std::move (params), std::move (outer_attrs),
13945 locus));
13946}
13947
13948// Parses a pseudo-binary infix function call expression.
13949template <typename ManagedTokenSource>
13950std::unique_ptr<AST::CallExpr>
13951Parser<ManagedTokenSource>::parse_function_call_expr (
13952 const_TokenPtr, std::unique_ptr<AST::Expr> function_expr,
13953 AST::AttrVec outer_attrs, ParseRestrictions)
13954{
13955 // parse function params (if they exist)
13956 std::vector<std::unique_ptr<AST::Expr>> params;
13957
13958 const_TokenPtr t = lexer.peek_token ();
13959 while (t->get_id () != RIGHT_PAREN)
13960 {
13961 std::unique_ptr<AST::Expr> param = parse_expr ();
13962 if (param == nullptr)
13963 {
13964 Error error (t->get_locus (),
13965 "failed to parse function param in function call");
13966 add_error (std::move (error));
13967
13968 return nullptr;
13969 }
13970 params.push_back (std::move (param));
13971
13972 if (lexer.peek_token ()->get_id () != COMMA)
13973 break;
13974
13975 lexer.skip_token ();
13976 t = lexer.peek_token ();
13977 }
13978
13979 // skip ')' at end of param list
13980 if (!skip_token (RIGHT_PAREN))
13981 {
13982 // skip somewhere?
13983 return nullptr;
13984 }
13985
13986 // TODO: check types. actually, do so during semantic analysis
d991a3f1 13987 location_t locus = function_expr->get_locus ();
32c8fb0e
JP
13988
13989 return std::unique_ptr<AST::CallExpr> (
13990 new AST::CallExpr (std::move (function_expr), std::move (params),
13991 std::move (outer_attrs), locus));
13992}
13993
13994/* Parses a macro invocation with a path in expression already parsed (but not
13995 * '!' token). */
13996template <typename ManagedTokenSource>
13997std::unique_ptr<AST::MacroInvocation>
13998Parser<ManagedTokenSource>::parse_macro_invocation_partial (
13999 AST::PathInExpression path, AST::AttrVec outer_attrs,
14000 ParseRestrictions restrictions)
14001{
14002 // macro invocation
14003 if (!skip_token (EXCLAM))
14004 {
14005 return nullptr;
14006 }
14007
14008 // convert PathInExpression to SimplePath - if this isn't possible, error
14009 AST::SimplePath converted_path = path.as_simple_path ();
14010 if (converted_path.is_empty ())
14011 {
14012 Error error (lexer.peek_token ()->get_locus (),
14013 "failed to parse simple path in macro invocation");
14014 add_error (std::move (error));
14015
14016 return nullptr;
14017 }
14018
14019 AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
14020
14021 rust_debug ("successfully parsed macro invocation (via partial)");
14022
80c68893 14023 location_t macro_locus = converted_path.get_locus ();
32c8fb0e 14024
51b607c2 14025 return AST::MacroInvocation::Regular (
32c8fb0e 14026 AST::MacroInvocData (std::move (converted_path), std::move (tok_tree)),
8bc4ce7c 14027 std::move (outer_attrs), macro_locus);
32c8fb0e
JP
14028}
14029
14030/* Parses a struct expr struct with a path in expression already parsed (but
14031 * not
14032 * '{' token). */
14033template <typename ManagedTokenSource>
14034std::unique_ptr<AST::StructExprStruct>
14035Parser<ManagedTokenSource>::parse_struct_expr_struct_partial (
14036 AST::PathInExpression path, AST::AttrVec outer_attrs)
14037{
14038 // assume struct expr struct (as struct-enum disambiguation requires name
14039 // lookup) again, make statement if final ';'
14040 if (!skip_token (LEFT_CURLY))
14041 {
14042 return nullptr;
14043 }
14044
14045 // parse inner attributes
14046 AST::AttrVec inner_attrs = parse_inner_attributes ();
14047
14048 // branch based on next token
14049 const_TokenPtr t = lexer.peek_token ();
80c68893 14050 location_t path_locus = path.get_locus ();
32c8fb0e
JP
14051 switch (t->get_id ())
14052 {
14053 case RIGHT_CURLY:
14054 // struct with no body
14055 lexer.skip_token ();
14056
14057 return std::unique_ptr<AST::StructExprStruct> (
14058 new AST::StructExprStruct (std::move (path), std::move (inner_attrs),
14059 std::move (outer_attrs), path_locus));
14060 case DOT_DOT:
14061 /* technically this would give a struct base-only struct, but this
14062 * algorithm should work too. As such, AST type not happening. */
14063 case IDENTIFIER:
fc1712be 14064 case HASH:
32c8fb0e
JP
14065 case INT_LITERAL: {
14066 // struct with struct expr fields
14067
14068 // parse struct expr fields
14069 std::vector<std::unique_ptr<AST::StructExprField>> fields;
14070
14071 while (t->get_id () != RIGHT_CURLY && t->get_id () != DOT_DOT)
14072 {
14073 std::unique_ptr<AST::StructExprField> field
14074 = parse_struct_expr_field ();
14075 if (field == nullptr)
14076 {
14077 Error error (t->get_locus (),
14078 "failed to parse struct (or enum) expr field");
14079 add_error (std::move (error));
14080
14081 return nullptr;
14082 }
14083
14084 // DEBUG:
14085 rust_debug ("struct/enum expr field validated to not be null");
14086
14087 fields.push_back (std::move (field));
14088
14089 // DEBUG:
14090 rust_debug ("struct/enum expr field pushed back");
14091
14092 if (lexer.peek_token ()->get_id () != COMMA)
14093 {
14094 // DEBUG:
14095 rust_debug ("lack of comma detected in struct/enum expr "
14096 "fields - break");
14097 break;
14098 }
14099 lexer.skip_token ();
14100
14101 // DEBUG:
14102 rust_debug ("struct/enum expr fields comma skipped ");
14103
14104 t = lexer.peek_token ();
14105 }
14106
14107 // DEBUG:
14108 rust_debug ("struct/enum expr about to parse struct base ");
14109
14110 // parse struct base if it exists
14111 AST::StructBase struct_base = AST::StructBase::error ();
14112 if (lexer.peek_token ()->get_id () == DOT_DOT)
14113 {
80c68893 14114 location_t dot_dot_location = lexer.peek_token ()->get_locus ();
32c8fb0e
JP
14115 lexer.skip_token ();
14116
14117 // parse required struct base expr
14118 std::unique_ptr<AST::Expr> base_expr = parse_expr ();
14119 if (base_expr == nullptr)
14120 {
14121 Error error (lexer.peek_token ()->get_locus (),
14122 "failed to parse struct base expression in struct "
14123 "expression");
14124 add_error (std::move (error));
14125
14126 return nullptr;
14127 }
14128
14129 // DEBUG:
14130 rust_debug ("struct/enum expr - parsed and validated base expr");
14131
14132 struct_base
14133 = AST::StructBase (std::move (base_expr), dot_dot_location);
14134
14135 // DEBUG:
14136 rust_debug ("assigned struct base to new struct base ");
14137 }
14138
14139 if (!skip_token (RIGHT_CURLY))
14140 {
14141 return nullptr;
14142 }
14143
14144 // DEBUG:
14145 rust_debug (
14146 "struct/enum expr skipped right curly - done and ready to return");
14147
14148 return std::unique_ptr<AST::StructExprStructFields> (
14149 new AST::StructExprStructFields (std::move (path), std::move (fields),
14150 path_locus, std::move (struct_base),
14151 std::move (inner_attrs),
14152 std::move (outer_attrs)));
14153 }
14154 default:
14155 add_error (
14156 Error (t->get_locus (),
14157 "unrecognised token %qs in struct (or enum) expression - "
14158 "expected %<}%>, identifier, integer literal, or %<..%>",
14159 t->get_token_description ()));
14160
14161 return nullptr;
14162 }
14163}
14164
14165/* Parses a struct expr tuple with a path in expression already parsed (but
14166 * not
14167 * '(' token).
14168 * FIXME: this currently outputs a call expr, as they cannot be disambiguated.
14169 * A better solution would be to just get this to call that function directly.
14170 * */
14171template <typename ManagedTokenSource>
14172std::unique_ptr<AST::CallExpr>
14173Parser<ManagedTokenSource>::parse_struct_expr_tuple_partial (
14174 AST::PathInExpression path, AST::AttrVec outer_attrs)
14175{
14176 if (!skip_token (LEFT_PAREN))
14177 {
14178 return nullptr;
14179 }
14180
14181 AST::AttrVec inner_attrs = parse_inner_attributes ();
14182
14183 std::vector<std::unique_ptr<AST::Expr>> exprs;
14184
14185 const_TokenPtr t = lexer.peek_token ();
14186 while (t->get_id () != RIGHT_PAREN)
14187 {
14188 // parse expression (required)
14189 std::unique_ptr<AST::Expr> expr = parse_expr ();
14190 if (expr == nullptr)
14191 {
14192 Error error (t->get_locus (), "failed to parse expression in "
14193 "struct (or enum) expression tuple");
14194 add_error (std::move (error));
14195
14196 return nullptr;
14197 }
14198 exprs.push_back (std::move (expr));
14199
14200 if (lexer.peek_token ()->get_id () != COMMA)
14201 break;
14202
14203 lexer.skip_token ();
14204
14205 t = lexer.peek_token ();
14206 }
14207
14208 if (!skip_token (RIGHT_PAREN))
14209 {
14210 return nullptr;
14211 }
14212
80c68893 14213 location_t path_locus = path.get_locus ();
32c8fb0e
JP
14214
14215 auto pathExpr = std::unique_ptr<AST::PathInExpression> (
14216 new AST::PathInExpression (std::move (path)));
14217
14218 return std::unique_ptr<AST::CallExpr> (
14219 new AST::CallExpr (std::move (pathExpr), std::move (exprs),
14220 std::move (outer_attrs), path_locus));
14221}
14222
14223/* Parses a path in expression with the first token passed as a parameter (as
14224 * it is skipped in token stream). Note that this only parses segment-first
14225 * paths, not global ones. */
14226template <typename ManagedTokenSource>
14227AST::PathInExpression
14228Parser<ManagedTokenSource>::parse_path_in_expression_pratt (const_TokenPtr tok)
14229{
14230 // HACK-y way of making up for pratt-parsing consuming first token
14231
14232 // DEBUG
14233 rust_debug ("current peek token when starting path pratt parse: '%s'",
14234 lexer.peek_token ()->get_token_description ());
14235
14236 // create segment vector
14237 std::vector<AST::PathExprSegment> segments;
14238
14239 std::string initial_str;
14240
14241 switch (tok->get_id ())
14242 {
14243 case IDENTIFIER:
14244 initial_str = tok->get_str ();
14245 break;
14246 case SUPER:
f1c7ce7e 14247 initial_str = Values::Keywords::SUPER;
32c8fb0e
JP
14248 break;
14249 case SELF:
f1c7ce7e 14250 initial_str = Values::Keywords::SELF;
32c8fb0e
JP
14251 break;
14252 case SELF_ALIAS:
f1c7ce7e 14253 initial_str = Values::Keywords::SELF_ALIAS;
32c8fb0e
JP
14254 break;
14255 case CRATE:
f1c7ce7e 14256 initial_str = Values::Keywords::CRATE;
32c8fb0e
JP
14257 break;
14258 case DOLLAR_SIGN:
14259 if (lexer.peek_token ()->get_id () == CRATE)
14260 {
14261 initial_str = "$crate";
14262 break;
14263 }
14264 gcc_fallthrough ();
14265 default:
14266 add_error (Error (tok->get_locus (),
14267 "unrecognised token %qs in path in expression",
14268 tok->get_token_description ()));
14269
14270 return AST::PathInExpression::create_error ();
14271 }
14272
14273 // parse required initial segment
14274 AST::PathExprSegment initial_segment (initial_str, tok->get_locus ());
14275 // parse generic args (and turbofish), if they exist
14276 /* use lookahead to determine if they actually exist (don't want to
14277 * accidently parse over next ident segment) */
14278 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
14279 && lexer.peek_token (1)->get_id () == LEFT_ANGLE)
14280 {
14281 // skip scope resolution
14282 lexer.skip_token ();
14283
14284 AST::GenericArgs generic_args = parse_path_generic_args ();
14285
14286 initial_segment
14287 = AST::PathExprSegment (AST::PathIdentSegment (initial_str,
14288 tok->get_locus ()),
14289 tok->get_locus (), std::move (generic_args));
14290 }
14291 if (initial_segment.is_error ())
14292 {
14293 // skip after somewhere?
14294 // don't necessarily throw error but yeah
14295
14296 // DEBUG
14297 rust_debug ("initial segment is error - returning null");
14298
14299 return AST::PathInExpression::create_error ();
14300 }
14301 segments.push_back (std::move (initial_segment));
14302
14303 // parse optional segments (as long as scope resolution operator exists)
14304 const_TokenPtr t = lexer.peek_token ();
14305 while (t->get_id () == SCOPE_RESOLUTION)
14306 {
14307 // skip scope resolution operator
14308 lexer.skip_token ();
14309
14310 // parse the actual segment - it is an error if it doesn't exist now
14311 AST::PathExprSegment segment = parse_path_expr_segment ();
14312 if (segment.is_error ())
14313 {
14314 // skip after somewhere?
14315 Error error (t->get_locus (),
14316 "could not parse path expression segment");
14317 add_error (std::move (error));
14318
14319 return AST::PathInExpression::create_error ();
14320 }
14321
14322 segments.push_back (std::move (segment));
14323
14324 t = lexer.peek_token ();
14325 }
14326
14327 // DEBUG:
14328 rust_debug (
14329 "current token (just about to return path to null denotation): '%s'",
14330 lexer.peek_token ()->get_token_description ());
14331
14332 return AST::PathInExpression (std::move (segments), {}, tok->get_locus (),
14333 false);
14334}
14335
14336// Parses a closure expression with pratt parsing (from null denotation).
14337template <typename ManagedTokenSource>
14338std::unique_ptr<AST::ClosureExpr>
14339Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok,
14340 AST::AttrVec outer_attrs)
14341{
14342 // TODO: does this need pratt parsing (for precedence)? probably not, but
14343 // idk
d991a3f1 14344 location_t locus = tok->get_locus ();
32c8fb0e
JP
14345 bool has_move = false;
14346 if (tok->get_id () == MOVE)
14347 {
14348 has_move = true;
14349 tok = lexer.peek_token ();
14350 lexer.skip_token ();
14351 // skip token and reassign
14352 }
14353
14354 // handle parameter list
14355 std::vector<AST::ClosureParam> params;
14356
14357 switch (tok->get_id ())
14358 {
14359 case OR:
14360 // no parameters, don't skip token
14361 break;
14362 case PIPE: {
14363 // actually may have parameters
14364 // don't skip token
14365 const_TokenPtr t = lexer.peek_token ();
14366 while (t->get_id () != PIPE)
14367 {
14368 AST::ClosureParam param = parse_closure_param ();
14369 if (param.is_error ())
14370 {
14371 // TODO is this really an error?
14372 Error error (t->get_locus (), "could not parse closure param");
14373 add_error (std::move (error));
14374
14375 return nullptr;
14376 }
14377 params.push_back (std::move (param));
14378
14379 if (lexer.peek_token ()->get_id () != COMMA)
14380 {
906e5553
PEP
14381 if (lexer.peek_token ()->get_id () == OR)
14382 lexer.split_current_token (PIPE, PIPE);
32c8fb0e
JP
14383 // not an error but means param list is done
14384 break;
14385 }
14386 // skip comma
14387 lexer.skip_token ();
14388
906e5553
PEP
14389 if (lexer.peek_token ()->get_id () == OR)
14390 lexer.split_current_token (PIPE, PIPE);
14391
32c8fb0e
JP
14392 t = lexer.peek_token ();
14393 }
14394
14395 if (!skip_token (PIPE))
14396 {
14397 return nullptr;
14398 }
14399 break;
14400 }
14401 default:
14402 add_error (Error (tok->get_locus (),
14403 "unexpected token %qs in closure expression - expected "
14404 "%<|%> or %<||%>",
14405 tok->get_token_description ()));
14406
14407 // skip somewhere?
14408 return nullptr;
14409 }
14410
14411 // again branch based on next token
14412 tok = lexer.peek_token ();
14413 if (tok->get_id () == RETURN_TYPE)
14414 {
14415 // must be return type closure with block expr
14416
14417 // skip "return type" token
14418 lexer.skip_token ();
14419
14420 // parse actual type, which is required
14421 std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
14422 if (type == nullptr)
14423 {
14424 // error
14425 Error error (tok->get_locus (), "failed to parse type for closure");
14426 add_error (std::move (error));
14427
14428 // skip somewhere?
14429 return nullptr;
14430 }
14431
14432 // parse block expr, which is required
14433 std::unique_ptr<AST::BlockExpr> block = parse_block_expr ();
14434 if (block == nullptr)
14435 {
14436 // error
14437 Error error (lexer.peek_token ()->get_locus (),
14438 "failed to parse block expr in closure");
14439 add_error (std::move (error));
14440
14441 // skip somewhere?
14442 return nullptr;
14443 }
14444
14445 return std::unique_ptr<AST::ClosureExprInnerTyped> (
14446 new AST::ClosureExprInnerTyped (std::move (type), std::move (block),
14447 std::move (params), locus, has_move,
14448 std::move (outer_attrs)));
14449 }
14450 else
14451 {
14452 // must be expr-only closure
14453
14454 // parse expr, which is required
14455 std::unique_ptr<AST::Expr> expr = parse_expr ();
14456 if (expr == nullptr)
14457 {
14458 Error error (tok->get_locus (),
14459 "failed to parse expression in closure");
14460 add_error (std::move (error));
14461
14462 // skip somewhere?
14463 return nullptr;
14464 }
14465
14466 return std::unique_ptr<AST::ClosureExprInner> (
14467 new AST::ClosureExprInner (std::move (expr), std::move (params), locus,
14468 has_move, std::move (outer_attrs)));
14469 }
14470}
14471
14472/* Parses a tuple index expression (pratt-parsed) from a 'float' token as a
14473 * result of lexer misidentification. */
14474template <typename ManagedTokenSource>
14475std::unique_ptr<AST::TupleIndexExpr>
14476Parser<ManagedTokenSource>::parse_tuple_index_expr_float (
14477 const_TokenPtr tok, std::unique_ptr<AST::Expr> tuple_expr,
14478 AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
14479{
14480 // only works on float literals
14481 if (tok->get_id () != FLOAT_LITERAL)
14482 return nullptr;
14483
14484 // DEBUG:
14485 rust_debug ("exact string form of float: '%s'", tok->get_str ().c_str ());
14486
14487 // get float string and remove dot and initial 0
14488 std::string index_str = tok->get_str ();
14489 index_str.erase (index_str.begin ());
14490
14491 // get int from string
14492 int index = atoi (index_str.c_str ());
14493
d991a3f1 14494 location_t locus = tuple_expr->get_locus ();
32c8fb0e
JP
14495
14496 return std::unique_ptr<AST::TupleIndexExpr> (
14497 new AST::TupleIndexExpr (std::move (tuple_expr), index,
14498 std::move (outer_attrs), locus));
14499}
14500
14501// Returns true if the next token is END, ELSE, or EOF;
14502template <typename ManagedTokenSource>
14503bool
14504Parser<ManagedTokenSource>::done_end_or_else ()
14505{
14506 const_TokenPtr t = lexer.peek_token ();
14507 return (t->get_id () == RIGHT_CURLY || t->get_id () == ELSE
14508 || t->get_id () == END_OF_FILE);
14509}
14510
14511// Returns true if the next token is END or EOF.
14512template <typename ManagedTokenSource>
14513bool
14514Parser<ManagedTokenSource>::done_end ()
14515{
14516 const_TokenPtr t = lexer.peek_token ();
14517 return (t->get_id () == RIGHT_CURLY || t->get_id () == END_OF_FILE);
14518}
32c8fb0e 14519} // namespace Rust