]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/rust/parse/rust-parse-impl.h
Update copyright years.
[thirdparty/gcc.git] / gcc / rust / parse / rust-parse-impl.h
CommitLineData
83ffe9cd 1// Copyright (C) 2020-2023 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
25#define INCLUDE_ALGORITHM
26#include "rust-diagnostics.h"
27#include "rust-make-unique.h"
28
29namespace Rust {
30// Left binding powers of operations.
31enum binding_powers
32{
33 // Highest priority
34 LBP_HIGHEST = 100,
35
36 LBP_PATH = 95,
37
38 LBP_METHOD_CALL = 90,
39
40 LBP_FIELD_EXPR = 85,
41
42 LBP_FUNCTION_CALL = 80,
43 LBP_ARRAY_REF = LBP_FUNCTION_CALL,
44
45 LBP_QUESTION_MARK = 75, // unary postfix - counts as left
46
47 LBP_UNARY_PLUS = 70, // Used only when the null denotation is +
48 LBP_UNARY_MINUS = LBP_UNARY_PLUS, // Used only when the null denotation is -
49 LBP_UNARY_ASTERISK = LBP_UNARY_PLUS, // deref operator - unary prefix
50 LBP_UNARY_EXCLAM = LBP_UNARY_PLUS,
51 LBP_UNARY_AMP = LBP_UNARY_PLUS,
52 LBP_UNARY_AMP_MUT = LBP_UNARY_PLUS,
53
54 LBP_AS = 65,
55
56 LBP_MUL = 60,
57 LBP_DIV = LBP_MUL,
58 LBP_MOD = LBP_MUL,
59
60 LBP_PLUS = 55,
61 LBP_MINUS = LBP_PLUS,
62
63 LBP_L_SHIFT = 50,
64 LBP_R_SHIFT = LBP_L_SHIFT,
65
66 LBP_AMP = 45,
67
68 LBP_CARET = 40,
69
70 LBP_PIPE = 35,
71
72 LBP_EQUAL = 30,
73 LBP_NOT_EQUAL = LBP_EQUAL,
74 LBP_SMALLER_THAN = LBP_EQUAL,
75 LBP_SMALLER_EQUAL = LBP_EQUAL,
76 LBP_GREATER_THAN = LBP_EQUAL,
77 LBP_GREATER_EQUAL = LBP_EQUAL,
78
79 LBP_LOGICAL_AND = 25,
80
81 LBP_LOGICAL_OR = 20,
82
83 LBP_DOT_DOT = 15,
84 LBP_DOT_DOT_EQ = LBP_DOT_DOT,
85
86 // TODO: note all these assig operators are RIGHT associative!
87 LBP_ASSIG = 10,
88 LBP_PLUS_ASSIG = LBP_ASSIG,
89 LBP_MINUS_ASSIG = LBP_ASSIG,
90 LBP_MULT_ASSIG = LBP_ASSIG,
91 LBP_DIV_ASSIG = LBP_ASSIG,
92 LBP_MOD_ASSIG = LBP_ASSIG,
93 LBP_AMP_ASSIG = LBP_ASSIG,
94 LBP_PIPE_ASSIG = LBP_ASSIG,
95 LBP_CARET_ASSIG = LBP_ASSIG,
96 LBP_L_SHIFT_ASSIG = LBP_ASSIG,
97 LBP_R_SHIFT_ASSIG = LBP_ASSIG,
98
99 // return, break, and closures as lowest priority?
100 LBP_RETURN = 5,
101 LBP_BREAK = LBP_RETURN,
102 LBP_CLOSURE = LBP_RETURN, // unary prefix operators
103
104#if 0
105 // rust precedences
106 // used for closures
107 PREC_CLOSURE = -40,
108 // used for break, continue, return, and yield
109 PREC_JUMP = -30,
110 // used for range (although weird comment in rustc about this)
111 PREC_RANGE = -10,
112 // used for binary operators mentioned below - also cast, colon (type),
113 // assign, assign_op
114 PREC_BINOP = FROM_ASSOC_OP,
115 // used for box, address_of, let, unary (again, weird comment on let)
116 PREC_PREFIX = 50,
117 // used for await, call, method call, field, index, try,
118 // inline asm, macro invocation
119 PREC_POSTFIX = 60,
120 // used for array, repeat, tuple, literal, path, paren, if,
121 // while, for, 'loop', match, block, try block, async, struct
122 PREC_PAREN = 99,
123 PREC_FORCE_PAREN = 100,
124#endif
125
126 // lowest priority
127 LBP_LOWEST = 0
128};
129
130/* Returns whether the token can start a type (i.e. there is a valid type
131 * beginning with the token). */
132inline bool
133can_tok_start_type (TokenId id)
134{
135 switch (id)
136 {
137 case EXCLAM:
138 case LEFT_SQUARE:
139 case LEFT_ANGLE:
140 case UNDERSCORE:
141 case ASTERISK:
142 case AMP:
143 case LIFETIME:
144 case IDENTIFIER:
145 case SUPER:
146 case SELF:
147 case SELF_ALIAS:
148 case CRATE:
149 case DOLLAR_SIGN:
150 case SCOPE_RESOLUTION:
151 case LEFT_PAREN:
152 case FOR:
153 case ASYNC:
154 case CONST:
155 case UNSAFE:
156 case EXTERN_TOK:
157 case FN_TOK:
158 case IMPL:
159 case DYN:
160 case QUESTION_MARK:
161 return true;
162 default:
163 return false;
164 }
165}
166
167/* Returns whether the token id is (or is likely to be) a right angle bracket.
168 * i.e. '>', '>>', '>=' and '>>=' tokens. */
169inline bool
170is_right_angle_tok (TokenId id)
171{
172 switch (id)
173 {
174 case RIGHT_ANGLE:
175 case RIGHT_SHIFT:
176 case GREATER_OR_EQUAL:
177 case RIGHT_SHIFT_EQ:
178 return true;
179 default:
180 return false;
181 }
182}
183
184/* HACK-y special handling for skipping a right angle token at the end of
185 * generic arguments.
186 * Currently, this replaces the "current token" with one that is identical
187 * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad
188 * for several reasons - it modifies the token stream to something that
189 * actually doesn't make syntactic sense, it may not worked if the token
190 * has already been skipped, etc. It was done because it would not
191 * actually require inserting new items into the token stream (which I
192 * thought would take more work to not mess up) and because I wasn't sure
193 * if the "already seen right angle" flag in the parser would work
194 * correctly.
195 * Those two other approaches listed are in my opinion actually better
196 * long-term - insertion is probably best as it reflects syntactically
197 * what occurs. On the other hand, I need to do a code audit to make sure
198 * that insertion doesn't mess anything up. So that's a FIXME. */
199template <typename ManagedTokenSource>
200bool
201Parser<ManagedTokenSource>::skip_generics_right_angle ()
202{
203 /* OK, new great idea. Have a lexer method called
204 * "split_current_token(TokenType newLeft, TokenType newRight)", which is
205 * called here with whatever arguments are appropriate. That lexer method
206 * handles "replacing" the current token with the "newLeft" and "inserting"
207 * the next token with the "newRight" (and creating a location, etc. for it)
208 */
209
210 /* HACK: special handling for right shift '>>', greater or equal '>=', and
211 * right shift assig */
212 // '>>='
213 const_TokenPtr tok = lexer.peek_token ();
214 switch (tok->get_id ())
215 {
216 case RIGHT_ANGLE:
217 // this is good - skip token
218 lexer.skip_token ();
219 return true;
220 case RIGHT_SHIFT: {
221 // new implementation that should be better
222 lexer.split_current_token (RIGHT_ANGLE, RIGHT_ANGLE);
223 lexer.skip_token ();
224 return true;
225 }
226 case GREATER_OR_EQUAL: {
227 // new implementation that should be better
228 lexer.split_current_token (RIGHT_ANGLE, EQUAL);
229 lexer.skip_token ();
230 return true;
231 }
232 case RIGHT_SHIFT_EQ: {
233 // new implementation that should be better
234 lexer.split_current_token (RIGHT_ANGLE, GREATER_OR_EQUAL);
235 lexer.skip_token ();
236 return true;
237 }
238 default:
239 add_error (Error (tok->get_locus (),
240 "expected %<>%> at end of generic argument - found %qs",
241 tok->get_token_description ()));
242 return false;
243 }
244}
245
246/* Gets left binding power for specified token.
247 * Not suitable for use at the moment or possibly ever because binding power
248 * cannot be purely determined from operator token with Rust grammar - e.g.
249 * method call and field access have
250 * different left binding powers but the same operator token. */
251template <typename ManagedTokenSource>
252int
253Parser<ManagedTokenSource>::left_binding_power (const_TokenPtr token)
254{
255 // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
256 switch (token->get_id ())
257 {
258 /* TODO: issue here - distinguish between method calls and field access
259 * somehow? Also would have to distinguish between paths and function
260 * calls (:: operator), maybe more stuff. */
261 /* Current plan for tackling LBP - don't do it based on token, use
262 * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr
263 * and handle other expressions without it. rustc only considers
264 * arithmetic, logical/relational, 'as',
265 * '?=', ranges, colons, and assignment to have operator precedence and
266 * associativity rules applicable. It then has
267 * a separate "ExprPrecedence" that also includes binary operators. */
268
269 // TODO: handle operator overloading - have a function replace the
270 // operator?
271
272 /*case DOT:
273 return LBP_DOT;*/
274
275 case SCOPE_RESOLUTION:
276 rust_debug (
277 "possible error - looked up LBP of scope resolution operator. should "
278 "be handled elsewhere.");
279 return LBP_PATH;
280
281 /* Resolved by lookahead HACK that should work with current code. If next
282 * token is identifier and token after that isn't parenthesised expression
283 * list, it is a field reference. */
284 case DOT:
285 if (lexer.peek_token (1)->get_id () == IDENTIFIER
286 && lexer.peek_token (2)->get_id () != LEFT_PAREN)
287 {
288 return LBP_FIELD_EXPR;
289 }
290 return LBP_METHOD_CALL;
291
292 case LEFT_PAREN:
293 return LBP_FUNCTION_CALL;
294
295 case LEFT_SQUARE:
296 return LBP_ARRAY_REF;
297
298 // postfix question mark (i.e. error propagation expression)
299 case QUESTION_MARK:
300 return LBP_QUESTION_MARK;
301
302 case AS:
303 return LBP_AS;
304
305 case ASTERISK:
306 return LBP_MUL;
307 case DIV:
308 return LBP_DIV;
309 case PERCENT:
310 return LBP_MOD;
311
312 case PLUS:
313 return LBP_PLUS;
314 case MINUS:
315 return LBP_MINUS;
316
317 case LEFT_SHIFT:
318 return LBP_L_SHIFT;
319 case RIGHT_SHIFT:
320 return LBP_R_SHIFT;
321
322 // binary & operator
323 case AMP:
324 return LBP_AMP;
325
326 // binary ^ operator
327 case CARET:
328 return LBP_CARET;
329
330 // binary | operator
331 case PIPE:
332 return LBP_PIPE;
333
334 case EQUAL_EQUAL:
335 return LBP_EQUAL;
336 case NOT_EQUAL:
337 return LBP_NOT_EQUAL;
338 case RIGHT_ANGLE:
339 return LBP_GREATER_THAN;
340 case GREATER_OR_EQUAL:
341 return LBP_GREATER_EQUAL;
342 case LEFT_ANGLE:
343 return LBP_SMALLER_THAN;
344 case LESS_OR_EQUAL:
345 return LBP_SMALLER_EQUAL;
346
347 case LOGICAL_AND:
348 return LBP_LOGICAL_AND;
349
350 case OR:
351 return LBP_LOGICAL_OR;
352
353 case DOT_DOT:
354 return LBP_DOT_DOT;
355
356 case DOT_DOT_EQ:
357 return LBP_DOT_DOT_EQ;
358
359 case EQUAL:
360 return LBP_ASSIG;
361 case PLUS_EQ:
362 return LBP_PLUS_ASSIG;
363 case MINUS_EQ:
364 return LBP_MINUS_ASSIG;
365 case ASTERISK_EQ:
366 return LBP_MULT_ASSIG;
367 case DIV_EQ:
368 return LBP_DIV_ASSIG;
369 case PERCENT_EQ:
370 return LBP_MOD_ASSIG;
371 case AMP_EQ:
372 return LBP_AMP_ASSIG;
373 case PIPE_EQ:
374 return LBP_PIPE_ASSIG;
375 case CARET_EQ:
376 return LBP_CARET_ASSIG;
377 case LEFT_SHIFT_EQ:
378 return LBP_L_SHIFT_ASSIG;
379 case RIGHT_SHIFT_EQ:
380 return LBP_R_SHIFT_ASSIG;
381
382 /* HACK: float literal due to lexer misidentifying a dot then an integer as
383 * a float */
384 case FLOAT_LITERAL:
385 return LBP_FIELD_EXPR;
386 // field expr is same as tuple expr in precedence, i imagine
387 // TODO: is this needed anymore? lexer shouldn't do that anymore
388
389 // anything that can't appear in an infix position is given lowest priority
390 default:
391 return LBP_LOWEST;
392 }
393}
394
395// Returns true when current token is EOF.
396template <typename ManagedTokenSource>
397bool
398Parser<ManagedTokenSource>::done_end_of_file ()
399{
400 return lexer.peek_token ()->get_id () == END_OF_FILE;
401}
402
403// Parses a sequence of items within a module or the implicit top-level module
404// in a crate
405template <typename ManagedTokenSource>
406std::vector<std::unique_ptr<AST::Item>>
407Parser<ManagedTokenSource>::parse_items ()
408{
409 std::vector<std::unique_ptr<AST::Item>> items;
410
411 const_TokenPtr t = lexer.peek_token ();
412 while (t->get_id () != END_OF_FILE)
413 {
414 std::unique_ptr<AST::Item> item = parse_item (false);
415 if (item == nullptr)
416 {
417 Error error (lexer.peek_token ()->get_locus (),
418 "failed to parse item in crate");
419 add_error (std::move (error));
420
421 // TODO: should all items be cleared?
422 items = std::vector<std::unique_ptr<AST::Item>> ();
423 break;
424 }
425
426 items.push_back (std::move (item));
427
428 t = lexer.peek_token ();
429 }
430
431 return items;
432}
433
434// Parses a crate (compilation unit) - entry point
435template <typename ManagedTokenSource>
436std::unique_ptr<AST::Crate>
437Parser<ManagedTokenSource>::parse_crate ()
438{
439 // parse inner attributes
440 AST::AttrVec inner_attrs = parse_inner_attributes ();
441
442 // parse items
443 std::vector<std::unique_ptr<AST::Item>> items = parse_items ();
444
445 // emit all errors
446 for (const auto &error : error_table)
447 error.emit_error ();
448
449 return std::unique_ptr<AST::Crate> (
450 new AST::Crate (std::move (items), std::move (inner_attrs)));
451}
452
453// Parse a contiguous block of inner attributes.
454template <typename ManagedTokenSource>
455AST::AttrVec
456Parser<ManagedTokenSource>::parse_inner_attributes ()
457{
458 AST::AttrVec inner_attributes;
459
460 // only try to parse it if it starts with "#!" not only "#"
461 while ((lexer.peek_token ()->get_id () == HASH
462 && lexer.peek_token (1)->get_id () == EXCLAM)
463 || lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
464 {
465 AST::Attribute inner_attr = parse_inner_attribute ();
466
467 /* Ensure only valid inner attributes are added to the inner_attributes
468 * list */
469 if (!inner_attr.is_empty ())
470 {
471 inner_attributes.push_back (std::move (inner_attr));
472 }
473 else
474 {
475 /* If no more valid inner attributes, break out of loop (only
476 * contiguous inner attributes parsed). */
477 break;
478 }
479 }
480
481 inner_attributes.shrink_to_fit ();
482 return inner_attributes;
483}
484
485// Parse a inner or outer doc comment into an doc attribute
486template <typename ManagedTokenSource>
487AST::Attribute
488Parser<ManagedTokenSource>::parse_doc_comment ()
489{
490 const_TokenPtr token = lexer.peek_token ();
491 Location locus = token->get_locus ();
492 AST::SimplePathSegment segment ("doc", locus);
493 std::vector<AST::SimplePathSegment> segments;
494 segments.push_back (std::move (segment));
495 AST::SimplePath attr_path (std::move (segments), false, locus);
496 AST::LiteralExpr lit_expr (token->get_str (), AST::Literal::STRING,
497 PrimitiveCoreType::CORETYPE_STR, {}, locus);
498 std::unique_ptr<AST::AttrInput> attr_input (
499 new AST::AttrInputLiteral (std::move (lit_expr)));
500 lexer.skip_token ();
501 return AST::Attribute (std::move (attr_path), std::move (attr_input), locus);
502}
503
504// Parse a single inner attribute.
505template <typename ManagedTokenSource>
506AST::Attribute
507Parser<ManagedTokenSource>::parse_inner_attribute ()
508{
509 if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
510 return parse_doc_comment ();
511
512 if (lexer.peek_token ()->get_id () != HASH)
513 {
514 Error error (lexer.peek_token ()->get_locus (),
515 "BUG: token %<#%> is missing, but %<parse_inner_attribute%> "
516 "was invoked");
517 add_error (std::move (error));
518
519 return AST::Attribute::create_empty ();
520 }
521 lexer.skip_token ();
522
523 if (lexer.peek_token ()->get_id () != EXCLAM)
524 {
525 Error error (lexer.peek_token ()->get_locus (),
526 "expected %<!%> or %<[%> for inner attribute");
527 add_error (std::move (error));
528
529 return AST::Attribute::create_empty ();
530 }
531 lexer.skip_token ();
532
533 if (!skip_token (LEFT_SQUARE))
534 return AST::Attribute::create_empty ();
535
536 AST::Attribute actual_attribute = parse_attribute_body ();
537
538 if (!skip_token (RIGHT_SQUARE))
539 return AST::Attribute::create_empty ();
540
541 return actual_attribute;
542}
543
544// Parses the body of an attribute (inner or outer).
545template <typename ManagedTokenSource>
546AST::Attribute
547Parser<ManagedTokenSource>::parse_attribute_body ()
548{
549 Location locus = lexer.peek_token ()->get_locus ();
550
551 AST::SimplePath attr_path = parse_simple_path ();
552 // ensure path is valid to parse attribute input
553 if (attr_path.is_empty ())
554 {
555 Error error (lexer.peek_token ()->get_locus (),
556 "empty simple path in attribute");
557 add_error (std::move (error));
558
559 // Skip past potential further info in attribute (i.e. attr_input)
560 skip_after_end_attribute ();
561 return AST::Attribute::create_empty ();
562 }
563
564 std::unique_ptr<AST::AttrInput> attr_input = parse_attr_input ();
565 // AttrInput is allowed to be null, so no checks here
566
567 return AST::Attribute (std::move (attr_path), std::move (attr_input), locus);
568}
569
570/* Determines whether token is a valid simple path segment. This does not
571 * include scope resolution operators. */
572inline bool
573is_simple_path_segment (TokenId id)
574{
575 switch (id)
576 {
577 case IDENTIFIER:
578 case SUPER:
579 case SELF:
580 case CRATE:
581 return true;
582 case DOLLAR_SIGN:
583 // assume that dollar sign leads to $crate
584 return true;
585 default:
586 return false;
587 }
588}
589
590// Parses a SimplePath AST node, if it exists. Does nothing otherwise.
591template <typename ManagedTokenSource>
592AST::SimplePath
593Parser<ManagedTokenSource>::parse_simple_path ()
594{
595 bool has_opening_scope_resolution = false;
596 Location locus = Linemap::unknown_location ();
597
598 // don't parse anything if not a path upfront
599 if (!is_simple_path_segment (lexer.peek_token ()->get_id ())
600 && !is_simple_path_segment (lexer.peek_token (1)->get_id ()))
601 return AST::SimplePath::create_empty ();
602
603 /* Checks for opening scope resolution (i.e. global scope fully-qualified
604 * path) */
605 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
606 {
607 has_opening_scope_resolution = true;
608
609 locus = lexer.peek_token ()->get_locus ();
610
611 lexer.skip_token ();
612 }
613
614 // Parse single required simple path segment
615 AST::SimplePathSegment segment = parse_simple_path_segment ();
616
617 // get location if not gotten already
618 if (locus == Linemap::unknown_location ())
619 locus = segment.get_locus ();
620
621 std::vector<AST::SimplePathSegment> segments;
622
623 // Return empty vector if first, actually required segment is an error
624 if (segment.is_error ())
625 return AST::SimplePath::create_empty ();
626
627 segments.push_back (std::move (segment));
628
629 // Parse all other simple path segments
630 while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
631 {
632 // Skip scope resolution operator
633 lexer.skip_token ();
634
635 AST::SimplePathSegment new_segment = parse_simple_path_segment ();
636
637 // Return path as currently constructed if segment in error state.
638 if (new_segment.is_error ())
639 break;
640
641 segments.push_back (std::move (new_segment));
642 }
643
644 // DEBUG: check for any empty segments
645 for (const auto &seg : segments)
646 {
647 if (seg.is_error ())
648 {
649 rust_debug (
650 "when parsing simple path, somehow empty path segment was "
651 "not filtered out. Path begins with '%s'",
652 segments.at (0).as_string ().c_str ());
653 }
654 }
655
656 return AST::SimplePath (std::move (segments), has_opening_scope_resolution,
657 locus);
658 /* TODO: now that is_simple_path_segment exists, could probably start
659 * actually making errors upon parse failure of segments and whatever */
660}
661
662/* Parses a single SimplePathSegment (does not handle the scope resolution
663 * operators) */
664template <typename ManagedTokenSource>
665AST::SimplePathSegment
666Parser<ManagedTokenSource>::parse_simple_path_segment ()
667{
668 const_TokenPtr t = lexer.peek_token ();
669 switch (t->get_id ())
670 {
671 case IDENTIFIER:
672 lexer.skip_token ();
673
674 return AST::SimplePathSegment (t->get_str (), t->get_locus ());
675 case SUPER:
676 lexer.skip_token ();
677
678 return AST::SimplePathSegment ("super", t->get_locus ());
679 case SELF:
680 lexer.skip_token ();
681
682 return AST::SimplePathSegment ("self", t->get_locus ());
683 case CRATE:
684 lexer.skip_token ();
685
686 return AST::SimplePathSegment ("crate", t->get_locus ());
687 case DOLLAR_SIGN:
688 if (lexer.peek_token (1)->get_id () == CRATE)
689 {
690 lexer.skip_token (1);
691
692 return AST::SimplePathSegment ("$crate", t->get_locus ());
693 }
694 gcc_fallthrough ();
695 default:
696 // do nothing but inactivates warning from gcc when compiling
697 /* could put the rust_error_at thing here but fallthrough (from failing
698 * $crate condition) isn't completely obvious if it is. */
699
700 // test prevent error
701 return AST::SimplePathSegment::create_error ();
702 }
703 gcc_unreachable ();
704 /*rust_error_at(
705 t->get_locus(), "invalid token '%s' in simple path segment",
706 t->get_token_description());*/
707 // this is not necessarily an error, e.g. end of path
708 // return AST::SimplePathSegment::create_error();
709}
710
711// Parses a PathIdentSegment - an identifier segment of a non-SimplePath path.
712template <typename ManagedTokenSource>
713AST::PathIdentSegment
714Parser<ManagedTokenSource>::parse_path_ident_segment ()
715{
716 const_TokenPtr t = lexer.peek_token ();
717 switch (t->get_id ())
718 {
719 case IDENTIFIER:
720 lexer.skip_token ();
721
722 return AST::PathIdentSegment (t->get_str (), t->get_locus ());
723 case SUPER:
724 lexer.skip_token ();
725
726 return AST::PathIdentSegment ("super", t->get_locus ());
727 case SELF:
728 lexer.skip_token ();
729
730 return AST::PathIdentSegment ("self", t->get_locus ());
731 case SELF_ALIAS:
732 lexer.skip_token ();
733
734 return AST::PathIdentSegment ("Self", t->get_locus ());
735 case CRATE:
736 lexer.skip_token ();
737
738 return AST::PathIdentSegment ("crate", t->get_locus ());
739 case DOLLAR_SIGN:
740 if (lexer.peek_token (1)->get_id () == CRATE)
741 {
742 lexer.skip_token (1);
743
744 return AST::PathIdentSegment ("$crate", t->get_locus ());
745 }
746 gcc_fallthrough ();
747 default:
748 /* do nothing but inactivates warning from gcc when compiling
749 * could put the error_at thing here but fallthrough (from failing $crate
750 * condition) isn't completely obvious if it is. */
751
752 // test prevent error
753 return AST::PathIdentSegment::create_error ();
754 }
755 gcc_unreachable ();
756 // not necessarily an error
757}
758
759// Parses an AttrInput AST node (polymorphic, as AttrInput is abstract)
760template <typename ManagedTokenSource>
761std::unique_ptr<AST::AttrInput>
762Parser<ManagedTokenSource>::parse_attr_input ()
763{
764 const_TokenPtr t = lexer.peek_token ();
765 switch (t->get_id ())
766 {
767 case LEFT_PAREN:
768 case LEFT_SQUARE:
769 case LEFT_CURLY: {
770 // must be a delimited token tree, so parse that
771 std::unique_ptr<AST::AttrInput> input_tree (
772 new AST::DelimTokenTree (parse_delim_token_tree ()));
773
774 // TODO: potential checks on DelimTokenTree before returning
775
776 return input_tree;
777 }
778 case EQUAL: {
779 // = LiteralExpr
780 lexer.skip_token ();
781
782 t = lexer.peek_token ();
783
784 /* Ensure token is a "literal expression" (literally only a literal
785 * token of any type) */
786 if (!t->is_literal ())
787 {
788 Error error (
789 t->get_locus (),
790 "unknown token %qs in attribute body - literal expected",
791 t->get_token_description ());
792 add_error (std::move (error));
793
794 skip_after_end_attribute ();
795 return nullptr;
796 }
797
798 AST::Literal::LitType lit_type = AST::Literal::STRING;
799 // Crappy mapping of token type to literal type
800 switch (t->get_id ())
801 {
802 case INT_LITERAL:
803 lit_type = AST::Literal::INT;
804 break;
805 case FLOAT_LITERAL:
806 lit_type = AST::Literal::FLOAT;
807 break;
808 case CHAR_LITERAL:
809 lit_type = AST::Literal::CHAR;
810 break;
811 case BYTE_CHAR_LITERAL:
812 lit_type = AST::Literal::BYTE;
813 break;
814 case BYTE_STRING_LITERAL:
815 lit_type = AST::Literal::BYTE_STRING;
816 break;
817 case STRING_LITERAL:
818 default:
819 lit_type = AST::Literal::STRING;
820 break; // TODO: raw string? don't eliminate it from lexer?
821 }
822
823 // create actual LiteralExpr
824 AST::LiteralExpr lit_expr (t->get_str (), lit_type, t->get_type_hint (),
825 {}, t->get_locus ());
826 lexer.skip_token ();
827
828 std::unique_ptr<AST::AttrInput> attr_input_lit (
829 new AST::AttrInputLiteral (std::move (lit_expr)));
830
831 // do checks or whatever? none required, really
832
833 // FIXME: shouldn't a skip token be required here?
834
835 return attr_input_lit;
836 }
837 break;
838 case RIGHT_SQUARE:
839 // means AttrInput is missing, which is allowed
840 return nullptr;
841 default:
842 add_error (
843 Error (t->get_locus (),
844 "unknown token %qs in attribute body - attribute input or "
845 "none expected",
846 t->get_token_description ()));
847
848 skip_after_end_attribute ();
849 return nullptr;
850 }
851 gcc_unreachable ();
852 // TODO: find out how to stop gcc error on "no return value"
853}
854
855/* Returns true if the token id matches the delimiter type. Note that this only
856 * operates for END delimiter tokens. */
857inline bool
858token_id_matches_delims (TokenId token_id, AST::DelimType delim_type)
859{
860 return ((token_id == RIGHT_PAREN && delim_type == AST::PARENS)
861 || (token_id == RIGHT_SQUARE && delim_type == AST::SQUARE)
862 || (token_id == RIGHT_CURLY && delim_type == AST::CURLY));
863}
864
865/* Returns true if the likely result of parsing the next few tokens is a path.
866 * Not guaranteed, though, especially in the case of syntax errors. */
867inline bool
868is_likely_path_next (TokenId next_token_id)
869{
870 switch (next_token_id)
871 {
872 case IDENTIFIER:
873 case SUPER:
874 case SELF:
875 case SELF_ALIAS:
876 case CRATE:
877 // maybe - maybe do extra check. But then requires another TokenId.
878 case DOLLAR_SIGN:
879 case SCOPE_RESOLUTION:
880 return true;
881 default:
882 return false;
883 }
884}
885
886// Parses a delimited token tree
887template <typename ManagedTokenSource>
888AST::DelimTokenTree
889Parser<ManagedTokenSource>::parse_delim_token_tree ()
890{
891 const_TokenPtr t = lexer.peek_token ();
892 lexer.skip_token ();
893 Location initial_loc = t->get_locus ();
894
895 // save delim type to ensure it is reused later
896 AST::DelimType delim_type = AST::PARENS;
897
898 // Map tokens to DelimType
899 switch (t->get_id ())
900 {
901 case LEFT_PAREN:
902 delim_type = AST::PARENS;
903 break;
904 case LEFT_SQUARE:
905 delim_type = AST::SQUARE;
906 break;
907 case LEFT_CURLY:
908 delim_type = AST::CURLY;
909 break;
910 default:
911 add_error (Error (t->get_locus (),
912 "unexpected token %qs - expecting delimiters (for a "
913 "delimited token tree)",
914 t->get_token_description ()));
915
916 return AST::DelimTokenTree::create_empty ();
917 }
918
919 // parse actual token tree vector - 0 or more
920 std::vector<std::unique_ptr<AST::TokenTree>> token_trees_in_tree;
921 auto delim_open
922 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
923 token_trees_in_tree.push_back (std::move (delim_open));
924
925 // repeat loop until finding the matching delimiter
926 t = lexer.peek_token ();
927 while (!token_id_matches_delims (t->get_id (), delim_type)
928 && t->get_id () != END_OF_FILE)
929 {
930 std::unique_ptr<AST::TokenTree> tok_tree = parse_token_tree ();
931
932 if (tok_tree == nullptr)
933 {
934 // TODO: is this error handling appropriate?
935 Error error (
936 t->get_locus (),
937 "failed to parse token tree in delimited token tree - found %qs",
938 t->get_token_description ());
939 add_error (std::move (error));
940
941 return AST::DelimTokenTree::create_empty ();
942 }
943
944 token_trees_in_tree.push_back (std::move (tok_tree));
945
946 // lexer.skip_token();
947 t = lexer.peek_token ();
948 }
949 auto delim_close
950 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
951 token_trees_in_tree.push_back (std::move (delim_close));
952
953 AST::DelimTokenTree token_tree (delim_type, std::move (token_trees_in_tree),
954 initial_loc);
955
956 // parse end delimiters
957 t = lexer.peek_token ();
958
959 if (token_id_matches_delims (t->get_id (), delim_type))
960 {
961 // tokens match opening delimiter, so skip.
962 lexer.skip_token ();
963
964 // DEBUG
965 rust_debug ("finished parsing new delim token tree - peeked token is now "
966 "'%s' while t is '%s'",
967 lexer.peek_token ()->get_token_description (),
968 t->get_token_description ());
969
970 return token_tree;
971 }
972 else
973 {
974 // tokens don't match opening delimiters, so produce error
975 Error error (t->get_locus (),
976 "unexpected token %qs - expecting closing delimiter %qs "
977 "(for a delimited token tree)",
978 t->get_token_description (),
979 (delim_type == AST::PARENS
980 ? ")"
981 : (delim_type == AST::SQUARE ? "]" : "}")));
982 add_error (std::move (error));
983
984 /* return empty token tree despite possibly parsing valid token tree -
985 * TODO is this a good idea? */
986 return AST::DelimTokenTree::create_empty ();
987 }
988}
989
990/* Parses a TokenTree syntactical production. This is either a delimited token
991 * tree or a non-delimiter token. */
992template <typename ManagedTokenSource>
993std::unique_ptr<AST::TokenTree>
994Parser<ManagedTokenSource>::parse_token_tree ()
995{
996 const_TokenPtr t = lexer.peek_token ();
997
998 switch (t->get_id ())
999 {
1000 case LEFT_PAREN:
1001 case LEFT_SQUARE:
1002 case LEFT_CURLY:
1003 // Parse delimited token tree
1004 // TODO: use move rather than copy constructor
1005 return std::unique_ptr<AST::DelimTokenTree> (
1006 new AST::DelimTokenTree (parse_delim_token_tree ()));
1007 case RIGHT_PAREN:
1008 case RIGHT_SQUARE:
1009 case RIGHT_CURLY:
1010 // error - should not be called when this a token
1011 add_error (
1012 Error (t->get_locus (),
1013 "unexpected closing delimiter %qs - token tree requires "
1014 "either paired delimiters or non-delimiter tokens",
1015 t->get_token_description ()));
1016
1017 lexer.skip_token ();
1018 return nullptr;
1019 default:
1020 // parse token itself as TokenTree
1021 lexer.skip_token ();
1022 return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1023 }
1024}
1025
1026// Parses a single item
1027template <typename ManagedTokenSource>
1028std::unique_ptr<AST::Item>
1029Parser<ManagedTokenSource>::parse_item (bool called_from_statement)
1030{
1031 // has a "called_from_statement" parameter for better error message handling
1032
1033 // parse outer attributes for item
1034 AST::AttrVec outer_attrs = parse_outer_attributes ();
1035
1036 // TODO: decide how to deal with VisItem vs MacroItem dichotomy
1037 /* best current solution: catch all keywords that would imply a VisItem in a
1038 * switch and have MacroItem as a last resort */
1039
1040 const_TokenPtr t = lexer.peek_token ();
1041
1042 switch (t->get_id ())
1043 {
1044 case END_OF_FILE:
1045 // not necessarily an error, unless we just read outer
1046 // attributes which needs to be attached
1047 if (!outer_attrs.empty ())
1048 {
1049 Rust::AST::Attribute attr = outer_attrs.back ();
1050 Error error (attr.get_locus (),
1051 "expected item after outer attribute or doc comment");
1052 add_error (std::move (error));
1053 }
1054 return nullptr;
1055 case PUB:
1056 case MOD:
1057 case EXTERN_TOK:
1058 case USE:
1059 case FN_TOK:
1060 case TYPE:
1061 case STRUCT_TOK:
1062 case ENUM_TOK:
1063 case CONST:
1064 case STATIC_TOK:
1065 case TRAIT:
1066 case IMPL:
1067 /* TODO: implement union keyword but not really because of
1068 * context-dependence crappy hack way to parse a union written below to
1069 * separate it from the good code. */
1070 // case UNION:
1071 case UNSAFE: // maybe - unsafe traits are a thing
1072 // if any of these (should be all possible VisItem prefixes), parse a
1073 // VisItem
1074 return parse_vis_item (std::move (outer_attrs));
1075 break;
1076 case SUPER:
1077 case SELF:
1078 case CRATE:
1079 case DOLLAR_SIGN:
1080 // almost certainly macro invocation semi
1081 return parse_macro_item (std::move (outer_attrs));
1082 break;
1083 // crappy hack to do union "keyword"
1084 case IDENTIFIER:
1085 // TODO: ensure std::string and literal comparison works
1086 if (t->get_str () == "union"
1087 && lexer.peek_token (1)->get_id () == IDENTIFIER)
1088 {
1089 return parse_vis_item (std::move (outer_attrs));
1090 // or should this go straight to parsing union?
1091 }
1092 else if (t->get_str () == "macro_rules")
1093 {
1094 // macro_rules! macro item
1095 return parse_macro_item (std::move (outer_attrs));
1096 }
1097 else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
1098 || lexer.peek_token (1)->get_id () == EXCLAM)
1099 {
1100 /* path (probably) or macro invocation, so probably a macro invocation
1101 * semi */
1102 return parse_macro_item (std::move (outer_attrs));
1103 }
1104 gcc_fallthrough ();
1105 default:
1106 // otherwise unrecognised
1107 // return parse_macro_item(std::move(outer_attrs));
1108 add_error (Error (t->get_locus (),
1109 "unrecognised token %qs for start of %s",
1110 t->get_token_description (),
1111 called_from_statement ? "statement" : "item"));
1112
1113 // skip somewhere?
1114 return nullptr;
1115 break;
1116 }
1117}
1118
1119// Parses a contiguous block of outer attributes.
1120template <typename ManagedTokenSource>
1121AST::AttrVec
1122Parser<ManagedTokenSource>::parse_outer_attributes ()
1123{
1124 AST::AttrVec outer_attributes;
1125
1126 while (lexer.peek_token ()->get_id ()
1127 == HASH /* Can also be #!, which catches errors. */
1128 || lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT
1129 || lexer.peek_token ()->get_id ()
1130 == INNER_DOC_COMMENT) /* For error handling. */
1131 {
1132 AST::Attribute outer_attr = parse_outer_attribute ();
1133
1134 /* Ensure only valid outer attributes are added to the outer_attributes
1135 * list */
1136 if (!outer_attr.is_empty ())
1137 {
1138 outer_attributes.push_back (std::move (outer_attr));
1139 }
1140 else
1141 {
1142 /* If no more valid outer attributes, break out of loop (only
1143 * contiguous outer attributes parsed). */
1144 break;
1145 }
1146 }
1147
1148 outer_attributes.shrink_to_fit ();
1149 return outer_attributes;
1150
1151 /* TODO: this shares basically all code with parse_inner_attributes except
1152 * function call - find way of making it more modular? function pointer? */
1153}
1154
1155// Parse a single outer attribute.
1156template <typename ManagedTokenSource>
1157AST::Attribute
1158Parser<ManagedTokenSource>::parse_outer_attribute ()
1159{
1160 if (lexer.peek_token ()->get_id () == OUTER_DOC_COMMENT)
1161 return parse_doc_comment ();
1162
1163 if (lexer.peek_token ()->get_id () == INNER_DOC_COMMENT)
1164 {
1165 Error error (
1166 lexer.peek_token ()->get_locus (),
1167 "inner doc (%<//!%> or %</*!%>) only allowed at start of item "
1168 "and before any outer attribute or doc (%<#[%>, %<///%> or %</**%>)");
1169 add_error (std::move (error));
1170 lexer.skip_token ();
1171 return AST::Attribute::create_empty ();
1172 }
1173
1174 /* OuterAttribute -> '#' '[' Attr ']' */
1175
1176 if (lexer.peek_token ()->get_id () != HASH)
1177 return AST::Attribute::create_empty ();
1178
1179 lexer.skip_token ();
1180
1181 TokenId id = lexer.peek_token ()->get_id ();
1182 if (id != LEFT_SQUARE)
1183 {
1184 if (id == EXCLAM)
1185 {
1186 // this is inner attribute syntax, so throw error
1187 // inner attributes were either already parsed or not allowed here.
1188 Error error (
1189 lexer.peek_token ()->get_locus (),
1190 "token %<!%> found, indicating inner attribute definition. Inner "
1191 "attributes are not possible at this location");
1192 add_error (std::move (error));
1193 }
1194 return AST::Attribute::create_empty ();
1195 }
1196
1197 lexer.skip_token ();
1198
1199 AST::Attribute actual_attribute = parse_attribute_body ();
1200
1201 if (lexer.peek_token ()->get_id () != RIGHT_SQUARE)
1202 return AST::Attribute::create_empty ();
1203
1204 lexer.skip_token ();
1205
1206 return actual_attribute;
1207}
1208
1209// Parses a VisItem (item that can have non-default visibility).
1210template <typename ManagedTokenSource>
1211std::unique_ptr<AST::VisItem>
1212Parser<ManagedTokenSource>::parse_vis_item (AST::AttrVec outer_attrs)
1213{
1214 // parse visibility, which may or may not exist
1215 AST::Visibility vis = parse_visibility ();
1216
1217 // select VisItem to create depending on keyword
1218 const_TokenPtr t = lexer.peek_token ();
1219
1220 switch (t->get_id ())
1221 {
1222 case MOD:
1223 return parse_module (std::move (vis), std::move (outer_attrs));
1224 case EXTERN_TOK:
1225 // lookahead to resolve syntactical production
1226 t = lexer.peek_token (1);
1227
1228 switch (t->get_id ())
1229 {
1230 case CRATE:
1231 return parse_extern_crate (std::move (vis), std::move (outer_attrs));
1232 case FN_TOK: // extern function
1233 return parse_function (std::move (vis), std::move (outer_attrs));
1234 case LEFT_CURLY: // extern block
1235 return parse_extern_block (std::move (vis), std::move (outer_attrs));
1236 case STRING_LITERAL: // for specifying extern ABI
1237 // could be extern block or extern function, so more lookahead
1238 t = lexer.peek_token (2);
1239
1240 switch (t->get_id ())
1241 {
1242 case FN_TOK:
1243 return parse_function (std::move (vis), std::move (outer_attrs));
1244 case LEFT_CURLY:
1245 return parse_extern_block (std::move (vis),
1246 std::move (outer_attrs));
1247 default:
1248 add_error (
1249 Error (t->get_locus (),
1250 "unexpected token %qs in some sort of extern production",
1251 t->get_token_description ()));
1252
1253 lexer.skip_token (2); // TODO: is this right thing to do?
1254 return nullptr;
1255 }
1256 default:
1257 add_error (
1258 Error (t->get_locus (),
1259 "unexpected token %qs in some sort of extern production",
1260 t->get_token_description ()));
1261
1262 lexer.skip_token (1); // TODO: is this right thing to do?
1263 return nullptr;
1264 }
1265 case USE:
1266 return parse_use_decl (std::move (vis), std::move (outer_attrs));
1267 case FN_TOK:
1268 return parse_function (std::move (vis), std::move (outer_attrs));
1269 case TYPE:
1270 return parse_type_alias (std::move (vis), std::move (outer_attrs));
1271 case STRUCT_TOK:
1272 return parse_struct (std::move (vis), std::move (outer_attrs));
1273 case ENUM_TOK:
1274 return parse_enum (std::move (vis), std::move (outer_attrs));
1275 // TODO: implement union keyword but not really because of
1276 // context-dependence case UNION: crappy hack to do union "keyword"
1277 case IDENTIFIER:
1278 if (t->get_str () == "union"
1279 && lexer.peek_token (1)->get_id () == IDENTIFIER)
1280 {
1281 return parse_union (std::move (vis), std::move (outer_attrs));
1282 // or should item switch go straight to parsing union?
1283 }
1284 else
1285 {
1286 break;
1287 }
1288 case CONST:
1289 // lookahead to resolve syntactical production
1290 t = lexer.peek_token (1);
1291
1292 switch (t->get_id ())
1293 {
1294 case IDENTIFIER:
1295 case UNDERSCORE:
1296 return parse_const_item (std::move (vis), std::move (outer_attrs));
1297 case UNSAFE:
1298 case EXTERN_TOK:
1299 case FN_TOK:
1300 return parse_function (std::move (vis), std::move (outer_attrs));
1301 default:
1302 add_error (
1303 Error (t->get_locus (),
1304 "unexpected token %qs in some sort of const production",
1305 t->get_token_description ()));
1306
1307 lexer.skip_token (1); // TODO: is this right thing to do?
1308 return nullptr;
1309 }
1310 case STATIC_TOK:
1311 return parse_static_item (std::move (vis), std::move (outer_attrs));
1312 case TRAIT:
1313 return parse_trait (std::move (vis), std::move (outer_attrs));
1314 case IMPL:
1315 return parse_impl (std::move (vis), std::move (outer_attrs));
1316 case UNSAFE: // unsafe traits, unsafe functions, unsafe impls (trait impls),
1317 // lookahead to resolve syntactical production
1318 t = lexer.peek_token (1);
1319
1320 switch (t->get_id ())
1321 {
1322 case TRAIT:
1323 return parse_trait (std::move (vis), std::move (outer_attrs));
1324 case EXTERN_TOK:
1325 case FN_TOK:
1326 return parse_function (std::move (vis), std::move (outer_attrs));
1327 case IMPL:
1328 return parse_impl (std::move (vis), std::move (outer_attrs));
1329 default:
1330 add_error (
1331 Error (t->get_locus (),
1332 "unexpected token %qs in some sort of unsafe production",
1333 t->get_token_description ()));
1334
1335 lexer.skip_token (1); // TODO: is this right thing to do?
1336 return nullptr;
1337 }
1338 default:
1339 // otherwise vis item clearly doesn't exist, which is not an error
1340 // has a catch-all post-switch return to allow other breaks to occur
1341 break;
1342 }
1343 return nullptr;
1344}
1345
1346// Parses a MacroItem (either a MacroInvocationSemi or MacroRulesDefinition).
1347template <typename ManagedTokenSource>
1348std::unique_ptr<AST::MacroItem>
1349Parser<ManagedTokenSource>::parse_macro_item (AST::AttrVec outer_attrs)
1350{
1351 const_TokenPtr t = lexer.peek_token ();
1352
1353 /* dodgy way of detecting macro due to weird context-dependence thing.
1354 * probably can be improved */
1355 // TODO: ensure that string compare works properly
1356 if (t->get_id () == IDENTIFIER && t->get_str () == "macro_rules")
1357 {
1358 return parse_macro_rules_def (std::move (outer_attrs));
1359 }
1360 else
1361 {
1362 // DEBUG: TODO: remove
1363 rust_debug (
1364 "DEBUG - parse_macro_item called and token is not macro_rules");
1365 if (t->get_id () == IDENTIFIER)
1366 {
1367 rust_debug ("just add to last error: token is not macro_rules and is "
1368 "instead '%s'",
1369 t->get_str ().c_str ());
1370 }
1371 else
1372 {
1373 rust_debug ("just add to last error: token is not macro_rules and is "
1374 "not an identifier either - it is '%s'",
1375 t->get_token_description ());
1376 }
1377
1378 return parse_macro_invocation_semi (std::move (outer_attrs));
1379 }
1380}
1381
1382// Parses a macro rules definition syntax extension whatever thing.
1383template <typename ManagedTokenSource>
1384std::unique_ptr<AST::MacroRulesDefinition>
1385Parser<ManagedTokenSource>::parse_macro_rules_def (AST::AttrVec outer_attrs)
1386{
1387 // ensure that first token is identifier saying "macro_rules"
1388 const_TokenPtr t = lexer.peek_token ();
1389 if (t->get_id () != IDENTIFIER || t->get_str () != "macro_rules")
1390 {
1391 Error error (
1392 t->get_locus (),
1393 "macro rules definition does not start with %<macro_rules%>");
1394 add_error (std::move (error));
1395
1396 // skip after somewhere?
1397 return nullptr;
1398 }
1399 lexer.skip_token ();
1400 Location macro_locus = t->get_locus ();
1401
1402 if (!skip_token (EXCLAM))
1403 {
1404 // skip after somewhere?
1405 return nullptr;
1406 }
1407
1408 // parse macro name
1409 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
1410 if (ident_tok == nullptr)
1411 {
1412 return nullptr;
1413 }
1414 Identifier rule_name = ident_tok->get_str ();
1415
1416 // DEBUG
1417 rust_debug ("in macro rules def, about to parse parens.");
1418
1419 // save delim type to ensure it is reused later
1420 AST::DelimType delim_type = AST::PARENS;
1421
1422 // Map tokens to DelimType
1423 t = lexer.peek_token ();
1424 switch (t->get_id ())
1425 {
1426 case LEFT_PAREN:
1427 delim_type = AST::PARENS;
1428 break;
1429 case LEFT_SQUARE:
1430 delim_type = AST::SQUARE;
1431 break;
1432 case LEFT_CURLY:
1433 delim_type = AST::CURLY;
1434 break;
1435 default:
1436 add_error (Error (t->get_locus (),
1437 "unexpected token %qs - expecting delimiters (for a "
1438 "macro rules definition)",
1439 t->get_token_description ()));
1440
1441 return nullptr;
1442 }
1443 lexer.skip_token ();
1444
1445 // parse actual macro rules
1446 std::vector<AST::MacroRule> macro_rules;
1447
1448 // must be at least one macro rule, so parse it
1449 AST::MacroRule initial_rule = parse_macro_rule ();
1450 if (initial_rule.is_error ())
1451 {
1452 Error error (lexer.peek_token ()->get_locus (),
1453 "required first macro rule in macro rules definition "
1454 "could not be parsed");
1455 add_error (std::move (error));
1456
1457 // skip after somewhere?
1458 return nullptr;
1459 }
1460 macro_rules.push_back (std::move (initial_rule));
1461
1462 // DEBUG
1463 rust_debug ("successfully pushed back initial macro rule");
1464
1465 t = lexer.peek_token ();
1466 // parse macro rules
1467 while (t->get_id () == SEMICOLON)
1468 {
1469 // skip semicolon
1470 lexer.skip_token ();
1471
1472 // don't parse if end of macro rules
1473 if (token_id_matches_delims (lexer.peek_token ()->get_id (), delim_type))
1474 {
1475 // DEBUG
1476 rust_debug (
1477 "broke out of parsing macro rules loop due to finding delim");
1478
1479 break;
1480 }
1481
1482 // try to parse next rule
1483 AST::MacroRule rule = parse_macro_rule ();
1484 if (rule.is_error ())
1485 {
1486 Error error (lexer.peek_token ()->get_locus (),
1487 "failed to parse macro rule in macro rules definition");
1488 add_error (std::move (error));
1489
1490 return nullptr;
1491 }
1492
1493 macro_rules.push_back (std::move (rule));
1494
1495 // DEBUG
1496 rust_debug ("successfully pushed back another macro rule");
1497
1498 t = lexer.peek_token ();
1499 }
1500
1501 // parse end delimiters
1502 t = lexer.peek_token ();
1503 if (token_id_matches_delims (t->get_id (), delim_type))
1504 {
1505 // tokens match opening delimiter, so skip.
1506 lexer.skip_token ();
1507
1508 if (delim_type != AST::CURLY)
1509 {
1510 // skip semicolon at end of non-curly macro definitions
1511 if (!skip_token (SEMICOLON))
1512 {
1513 // as this is the end, allow recovery (probably) - may change
1514 return std::unique_ptr<AST::MacroRulesDefinition> (
1515 new AST::MacroRulesDefinition (
1516 std::move (rule_name), delim_type, std::move (macro_rules),
1517 std::move (outer_attrs), macro_locus));
1518 }
1519 }
1520
1521 return std::unique_ptr<AST::MacroRulesDefinition> (
1522 new AST::MacroRulesDefinition (std::move (rule_name), delim_type,
1523 std::move (macro_rules),
1524 std::move (outer_attrs), macro_locus));
1525 }
1526 else
1527 {
1528 // tokens don't match opening delimiters, so produce error
1529 Error error (t->get_locus (),
1530 "unexpected token %qs - expecting closing delimiter %qs "
1531 "(for a macro rules definition)",
1532 t->get_token_description (),
1533 (delim_type == AST::PARENS
1534 ? ")"
1535 : (delim_type == AST::SQUARE ? "]" : "}")));
1536 add_error (std::move (error));
1537
1538 /* return empty macro definiton despite possibly parsing mostly valid one
1539 * - TODO is this a good idea? */
1540 return nullptr;
1541 }
1542}
1543
1544// Parses a semi-coloned (except for full block) macro invocation item.
1545template <typename ManagedTokenSource>
1546std::unique_ptr<AST::MacroInvocation>
1547Parser<ManagedTokenSource>::parse_macro_invocation_semi (
1548 AST::AttrVec outer_attrs)
1549{
1550 Location macro_locus = lexer.peek_token ()->get_locus ();
1551 AST::SimplePath path = parse_simple_path ();
1552
1553 if (!skip_token (EXCLAM))
1554 {
1555 // skip after somewhere?
1556 return nullptr;
1557 }
1558
1559 // save delim type to ensure it is reused later
1560 AST::DelimType delim_type = AST::PARENS;
1561
1562 // Map tokens to DelimType
1563 const_TokenPtr t = lexer.peek_token ();
1564 switch (t->get_id ())
1565 {
1566 case LEFT_PAREN:
1567 delim_type = AST::PARENS;
1568 break;
1569 case LEFT_SQUARE:
1570 delim_type = AST::SQUARE;
1571 break;
1572 case LEFT_CURLY:
1573 delim_type = AST::CURLY;
1574 break;
1575 default:
1576 add_error (Error (t->get_locus (),
1577 "unexpected token %qs - expecting delimiters (for a "
1578 "macro invocation semi body)",
1579 t->get_token_description ()));
1580
1581 return nullptr;
1582 }
1583 Location tok_tree_locus = t->get_locus ();
1584 lexer.skip_token ();
1585
1586 // parse actual token trees
1587 std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
1588 auto delim_open
1589 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1590 token_trees.push_back (std::move (delim_open));
1591
1592 t = lexer.peek_token ();
1593 // parse token trees until the initial delimiter token is found again
1594 while (!token_id_matches_delims (t->get_id (), delim_type))
1595 {
1596 std::unique_ptr<AST::TokenTree> tree = parse_token_tree ();
1597
1598 if (tree == nullptr)
1599 {
1600 Error error (t->get_locus (),
1601 "failed to parse token tree for macro invocation semi "
1602 "- found %qs",
1603 t->get_token_description ());
1604 add_error (std::move (error));
1605
1606 return nullptr;
1607 }
1608
1609 token_trees.push_back (std::move (tree));
1610
1611 t = lexer.peek_token ();
1612 }
1613 auto delim_close
1614 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1615 token_trees.push_back (std::move (delim_close));
1616
1617 AST::DelimTokenTree delim_tok_tree (delim_type, std::move (token_trees),
1618 tok_tree_locus);
1619 AST::MacroInvocData invoc_data (std::move (path), std::move (delim_tok_tree));
1620
1621 // parse end delimiters
1622 t = lexer.peek_token ();
1623 if (token_id_matches_delims (t->get_id (), delim_type))
1624 {
1625 // tokens match opening delimiter, so skip.
1626 lexer.skip_token ();
1627
1628 if (delim_type != AST::CURLY)
1629 {
1630 // skip semicolon at end of non-curly macro invocation semis
1631 if (!skip_token (SEMICOLON))
1632 {
1633 // as this is the end, allow recovery (probably) - may change
1634
1635 return std::unique_ptr<AST::MacroInvocation> (
1636 new AST::MacroInvocation (std::move (invoc_data),
1637 std::move (outer_attrs), macro_locus,
1638 true));
1639 }
1640 }
1641
1642 // DEBUG:
1643 rust_debug ("skipped token is '%s', next token (current peek) is '%s'",
1644 t->get_token_description (),
1645 lexer.peek_token ()->get_token_description ());
1646
1647 return std::unique_ptr<AST::MacroInvocation> (
1648 new AST::MacroInvocation (std::move (invoc_data),
1649 std::move (outer_attrs), macro_locus, true));
1650 }
1651 else
1652 {
1653 // tokens don't match opening delimiters, so produce error
1654 Error error (t->get_locus (),
1655 "unexpected token %qs - expecting closing delimiter %qs "
1656 "(for a macro invocation semi)",
1657 t->get_token_description (),
1658 (delim_type == AST::PARENS
1659 ? ")"
1660 : (delim_type == AST::SQUARE ? "]" : "}")));
1661 add_error (std::move (error));
1662
1663 /* return empty macro invocation despite possibly parsing mostly valid one
1664 * - TODO is this a good idea? */
1665 return nullptr;
1666 }
1667}
1668
1669// Parses a non-semicoloned macro invocation (i.e. as pattern or expression).
1670template <typename ManagedTokenSource>
1671std::unique_ptr<AST::MacroInvocation>
1672Parser<ManagedTokenSource>::parse_macro_invocation (AST::AttrVec outer_attrs)
1673{
1674 // parse macro path
1675 AST::SimplePath macro_path = parse_simple_path ();
1676 if (macro_path.is_empty ())
1677 {
1678 Error error (lexer.peek_token ()->get_locus (),
1679 "failed to parse macro invocation path");
1680 add_error (std::move (error));
1681
1682 // skip?
1683 return nullptr;
1684 }
1685
1686 if (!skip_token (EXCLAM))
1687 {
1688 // skip after somewhere?
1689 return nullptr;
1690 }
1691
1692 // parse internal delim token tree
1693 AST::DelimTokenTree delim_tok_tree = parse_delim_token_tree ();
1694
1695 Location macro_locus = macro_path.get_locus ();
1696
1697 return std::unique_ptr<AST::MacroInvocation> (
1698 new AST::MacroInvocation (AST::MacroInvocData (std::move (macro_path),
1699 std::move (delim_tok_tree)),
1700 std::move (outer_attrs), macro_locus));
1701}
1702
1703// Parses a macro rule definition - does not parse semicolons.
1704template <typename ManagedTokenSource>
1705AST::MacroRule
1706Parser<ManagedTokenSource>::parse_macro_rule ()
1707{
1708 Location locus = lexer.peek_token ()->get_locus ();
1709
1710 // parse macro matcher
1711 AST::MacroMatcher matcher = parse_macro_matcher ();
1712
1713 if (matcher.is_error ())
1714 return AST::MacroRule::create_error (locus);
1715
1716 if (!skip_token (MATCH_ARROW))
1717 {
1718 // skip after somewhere?
1719 return AST::MacroRule::create_error (locus);
1720 }
1721
1722 // parse transcriber (this is just a delim token tree)
1723 Location token_tree_loc = lexer.peek_token ()->get_locus ();
1724 AST::MacroTranscriber transcriber (parse_delim_token_tree (), token_tree_loc);
1725
1726 return AST::MacroRule (std::move (matcher), std::move (transcriber), locus);
1727}
1728
1729// Parses a macro matcher (part of a macro rule definition).
1730template <typename ManagedTokenSource>
1731AST::MacroMatcher
1732Parser<ManagedTokenSource>::parse_macro_matcher ()
1733{
1734 // save delim type to ensure it is reused later
1735 AST::DelimType delim_type = AST::PARENS;
1736
1737 // DEBUG
1738 rust_debug ("begun parsing macro matcher");
1739
1740 // Map tokens to DelimType
1741 const_TokenPtr t = lexer.peek_token ();
1742 Location locus = t->get_locus ();
1743 switch (t->get_id ())
1744 {
1745 case LEFT_PAREN:
1746 delim_type = AST::PARENS;
1747 break;
1748 case LEFT_SQUARE:
1749 delim_type = AST::SQUARE;
1750 break;
1751 case LEFT_CURLY:
1752 delim_type = AST::CURLY;
1753 break;
1754 default:
1755 add_error (Error (
1756 t->get_locus (),
1757 "unexpected token %qs - expecting delimiters (for a macro matcher)",
1758 t->get_token_description ()));
1759
1760 return AST::MacroMatcher::create_error (t->get_locus ());
1761 }
1762 lexer.skip_token ();
1763
1764 // parse actual macro matches
1765 std::vector<std::unique_ptr<AST::MacroMatch>> matches;
1766 // Set of possible preceding macro matches to make sure follow-set
1767 // restrictions are respected.
1768 // TODO: Consider using std::reference_wrapper instead of raw pointers?
1769 std::vector<const AST::MacroMatch *> last_matches;
1770
1771 t = lexer.peek_token ();
1772 // parse token trees until the initial delimiter token is found again
1773 while (!token_id_matches_delims (t->get_id (), delim_type))
1774 {
1775 std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
1776
1777 if (match == nullptr)
1778 {
1779 Error error (
1780 t->get_locus (),
1781 "failed to parse macro match for macro matcher - found %qs",
1782 t->get_token_description ());
1783 add_error (std::move (error));
1784
1785 return AST::MacroMatcher::create_error (t->get_locus ());
1786 }
1787
1788 if (matches.size () > 0)
1789 {
1790 const auto *last_match = matches.back ().get ();
1791
1792 // We want to check if we are dealing with a zeroable repetition
1793 bool zeroable = false;
1794 if (last_match->get_macro_match_type ()
1795 == AST::MacroMatch::MacroMatchType::Repetition)
1796 {
1797 auto repetition
1798 = static_cast<const AST::MacroMatchRepetition *> (last_match);
1799
1800 if (repetition->get_op ()
1801 != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE)
1802 zeroable = true;
1803 }
1804
1805 if (!zeroable)
1806 last_matches.clear ();
1807
1808 last_matches.emplace_back (last_match);
1809
1810 for (auto last : last_matches)
1811 if (!is_match_compatible (*last, *match))
1812 return AST::MacroMatcher::create_error (
1813 match->get_match_locus ());
1814 }
1815
1816 matches.push_back (std::move (match));
1817
1818 // DEBUG
1819 rust_debug ("pushed back a match in macro matcher");
1820
1821 t = lexer.peek_token ();
1822 }
1823
1824 // parse end delimiters
1825 t = lexer.peek_token ();
1826 if (token_id_matches_delims (t->get_id (), delim_type))
1827 {
1828 // tokens match opening delimiter, so skip.
1829 lexer.skip_token ();
1830
1831 return AST::MacroMatcher (delim_type, std::move (matches), locus);
1832 }
1833 else
1834 {
1835 // tokens don't match opening delimiters, so produce error
1836 Error error (t->get_locus (),
1837 "unexpected token %qs - expecting closing delimiter %qs "
1838 "(for a macro matcher)",
1839 t->get_token_description (),
1840 (delim_type == AST::PARENS
1841 ? ")"
1842 : (delim_type == AST::SQUARE ? "]" : "}")));
1843 add_error (std::move (error));
1844
1845 /* return error macro matcher despite possibly parsing mostly correct one?
1846 * TODO is this the best idea? */
1847 return AST::MacroMatcher::create_error (t->get_locus ());
1848 }
1849}
1850
1851// Parses a macro match (syntax match inside a matcher in a macro rule).
1852template <typename ManagedTokenSource>
1853std::unique_ptr<AST::MacroMatch>
1854Parser<ManagedTokenSource>::parse_macro_match ()
1855{
1856 // branch based on token available
1857 const_TokenPtr t = lexer.peek_token ();
1858 switch (t->get_id ())
1859 {
1860 case LEFT_PAREN:
1861 case LEFT_SQUARE:
1862 case LEFT_CURLY: {
1863 // must be macro matcher as delimited
1864 AST::MacroMatcher matcher = parse_macro_matcher ();
1865 if (matcher.is_error ())
1866 {
1867 Error error (lexer.peek_token ()->get_locus (),
1868 "failed to parse macro matcher in macro match");
1869 add_error (std::move (error));
1870
1871 return nullptr;
1872 }
1873 return std::unique_ptr<AST::MacroMatcher> (
1874 new AST::MacroMatcher (std::move (matcher)));
1875 }
1876 case DOLLAR_SIGN: {
1877 // have to do more lookahead to determine if fragment or repetition
1878 const_TokenPtr t2 = lexer.peek_token (1);
1879 switch (t2->get_id ())
1880 {
1881 case ABSTRACT:
1882 case AS:
1883 case ASYNC:
1884 case BECOME:
1885 case BOX:
1886 case BREAK:
1887 case CONST:
1888 case CONTINUE:
1889 case CRATE:
1890 case DO:
1891 case DYN:
1892 case ELSE:
1893 case ENUM_TOK:
1894 case EXTERN_TOK:
1895 case FALSE_LITERAL:
1896 case FINAL_TOK:
1897 case FN_TOK:
1898 case FOR:
1899 case IF:
1900 case IMPL:
1901 case IN:
1902 case LET:
1903 case LOOP:
1904 case MACRO:
1905 case MATCH_TOK:
1906 case MOD:
1907 case MOVE:
1908 case MUT:
1909 case OVERRIDE_TOK:
1910 case PRIV:
1911 case PUB:
1912 case REF:
1913 case RETURN_TOK:
1914 case SELF_ALIAS:
1915 case SELF:
1916 case STATIC_TOK:
1917 case STRUCT_TOK:
1918 case SUPER:
1919 case TRAIT:
1920 case TRUE_LITERAL:
1921 case TRY:
1922 case TYPE:
1923 case TYPEOF:
1924 case UNSAFE:
1925 case UNSIZED:
1926 case USE:
1927 case VIRTUAL:
1928 case WHERE:
1929 case WHILE:
1930 case YIELD:
1931 case IDENTIFIER:
1932 // macro fragment
1933 return parse_macro_match_fragment ();
1934 case LEFT_PAREN:
1935 // macro repetition
1936 return parse_macro_match_repetition ();
1937 default:
1938 // error: unrecognised
1939 add_error (
1940 Error (t2->get_locus (),
1941 "unrecognised token combination %<$%s%> at start of "
1942 "macro match - did you mean %<$identifier%> or %<$(%>?",
1943 t2->get_token_description ()));
1944
1945 // skip somewhere?
1946 return nullptr;
1947 }
1948 }
1949 case RIGHT_PAREN:
1950 case RIGHT_SQUARE:
1951 case RIGHT_CURLY:
1952 // not allowed
1953 add_error (Error (
1954 t->get_locus (),
1955 "closing delimiters like %qs are not allowed at the start of a macro "
1956 "match",
1957 t->get_token_description ()));
1958
1959 // skip somewhere?
1960 return nullptr;
1961 default:
1962 // just the token
1963 lexer.skip_token ();
1964 return std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
1965 }
1966}
1967
1968// Parses a fragment macro match.
1969template <typename ManagedTokenSource>
1970std::unique_ptr<AST::MacroMatchFragment>
1971Parser<ManagedTokenSource>::parse_macro_match_fragment ()
1972{
1973 Location fragment_locus = lexer.peek_token ()->get_locus ();
1974 skip_token (DOLLAR_SIGN);
1975
1976 Identifier ident = "";
1977 auto identifier = lexer.peek_token ();
1978 if (identifier->has_str ())
1979 ident = identifier->get_str ();
1980 else
1981 ident = std::string (token_id_to_str (identifier->get_id ()));
1982
1983 if (ident.empty ())
1984 {
1985 Error error (lexer.peek_token ()->get_locus (),
1986 "missing identifier in macro match fragment");
1987 add_error (std::move (error));
1988
1989 return nullptr;
1990 }
1991 skip_token (identifier->get_id ());
1992
1993 if (!skip_token (COLON))
1994 {
1995 // skip after somewhere?
1996 return nullptr;
1997 }
1998
1999 // get MacroFragSpec for macro
2000 const_TokenPtr t = expect_token (IDENTIFIER);
2001 if (t == nullptr)
2002 return nullptr;
2003
2004 AST::MacroFragSpec frag
2005 = AST::MacroFragSpec::get_frag_spec_from_str (t->get_str ());
2006 if (frag.is_error ())
2007 {
2008 Error error (t->get_locus (),
2009 "invalid fragment specifier %qs in fragment macro match",
2010 t->get_str ().c_str ());
2011 add_error (std::move (error));
2012
2013 return nullptr;
2014 }
2015
2016 return std::unique_ptr<AST::MacroMatchFragment> (
2017 new AST::MacroMatchFragment (std::move (ident), frag, fragment_locus));
2018}
2019
2020// Parses a repetition macro match.
2021template <typename ManagedTokenSource>
2022std::unique_ptr<AST::MacroMatchRepetition>
2023Parser<ManagedTokenSource>::parse_macro_match_repetition ()
2024{
2025 skip_token (DOLLAR_SIGN);
2026 skip_token (LEFT_PAREN);
2027
2028 std::vector<std::unique_ptr<AST::MacroMatch>> matches;
2029
2030 // parse required first macro match
2031 std::unique_ptr<AST::MacroMatch> initial_match = parse_macro_match ();
2032 if (initial_match == nullptr)
2033 {
2034 Error error (
2035 lexer.peek_token ()->get_locus (),
2036 "could not parse required first macro match in macro match repetition");
2037 add_error (std::move (error));
2038
2039 // skip after somewhere?
2040 return nullptr;
2041 }
2042 matches.push_back (std::move (initial_match));
2043
2044 // parse optional later macro matches
2045 const_TokenPtr t = lexer.peek_token ();
2046 while (t->get_id () != RIGHT_PAREN)
2047 {
2048 std::unique_ptr<AST::MacroMatch> match = parse_macro_match ();
2049
2050 if (match == nullptr)
2051 {
2052 Error error (lexer.peek_token ()->get_locus (),
2053 "failed to parse macro match in macro match repetition");
2054 add_error (std::move (error));
2055
2056 return nullptr;
2057 }
2058
2059 matches.push_back (std::move (match));
2060
2061 t = lexer.peek_token ();
2062 }
2063
2064 if (!skip_token (RIGHT_PAREN))
2065 {
2066 // skip after somewhere?
2067 return nullptr;
2068 }
2069
2070 t = lexer.peek_token ();
2071 // see if separator token exists
2072 std::unique_ptr<AST::Token> separator = nullptr;
2073 switch (t->get_id ())
2074 {
2075 // repetition operators
2076 case ASTERISK:
2077 case PLUS:
2078 case QUESTION_MARK:
2079 // delimiters
2080 case LEFT_PAREN:
2081 case LEFT_CURLY:
2082 case LEFT_SQUARE:
2083 case RIGHT_PAREN:
2084 case RIGHT_CURLY:
2085 case RIGHT_SQUARE:
2086 // separator does not exist, so still null and don't skip token
2087 break;
2088 default:
2089 // separator does exist
2090 separator = std::unique_ptr<AST::Token> (new AST::Token (std::move (t)));
2091 lexer.skip_token ();
2092 break;
2093 }
2094
2095 // parse repetition operator
2096 t = lexer.peek_token ();
2097 AST::MacroMatchRepetition::MacroRepOp op = AST::MacroMatchRepetition::NONE;
2098 switch (t->get_id ())
2099 {
2100 case ASTERISK:
2101 op = AST::MacroMatchRepetition::ANY;
2102 lexer.skip_token ();
2103 break;
2104 case PLUS:
2105 op = AST::MacroMatchRepetition::ONE_OR_MORE;
2106 lexer.skip_token ();
2107 break;
2108 case QUESTION_MARK:
2109 op = AST::MacroMatchRepetition::ZERO_OR_ONE;
2110 lexer.skip_token ();
2111 break;
2112 default:
2113 add_error (
2114 Error (t->get_locus (),
2115 "expected macro repetition operator (%<*%>, %<+%>, or %<?%>) in "
2116 "macro match - found %qs",
2117 t->get_token_description ()));
2118
2119 // skip after somewhere?
2120 return nullptr;
2121 }
2122
2123 return std::unique_ptr<AST::MacroMatchRepetition> (
2124 new AST::MacroMatchRepetition (std::move (matches), op,
2125 std::move (separator), t->get_locus ()));
2126}
2127
2128/* Parses a visibility syntactical production (i.e. creating a non-default
2129 * visibility) */
2130template <typename ManagedTokenSource>
2131AST::Visibility
2132Parser<ManagedTokenSource>::parse_visibility ()
2133{
2134 // check for no visibility
2135 if (lexer.peek_token ()->get_id () != PUB)
2136 {
2137 return AST::Visibility::create_private ();
2138 }
2139
2140 lexer.skip_token ();
2141
2142 // create simple pub visibility if no parentheses
2143 if (lexer.peek_token ()->get_id () != LEFT_PAREN)
2144 {
2145 return AST::Visibility::create_public ();
2146 // or whatever
2147 }
2148
2149 lexer.skip_token ();
2150
2151 const_TokenPtr t = lexer.peek_token ();
2152 auto path_loc = t->get_locus ();
2153
2154 switch (t->get_id ())
2155 {
2156 case CRATE:
2157 lexer.skip_token ();
2158
2159 skip_token (RIGHT_PAREN);
2160
2161 return AST::Visibility::create_crate (path_loc);
2162 case SELF:
2163 lexer.skip_token ();
2164
2165 skip_token (RIGHT_PAREN);
2166
2167 return AST::Visibility::create_self (path_loc);
2168 case SUPER:
2169 lexer.skip_token ();
2170
2171 skip_token (RIGHT_PAREN);
2172
2173 return AST::Visibility::create_super (path_loc);
2174 case IN: {
2175 lexer.skip_token ();
2176
2177 // parse the "in" path as well
2178 AST::SimplePath path = parse_simple_path ();
2179 if (path.is_empty ())
2180 {
2181 Error error (lexer.peek_token ()->get_locus (),
2182 "missing path in pub(in path) visibility");
2183 add_error (std::move (error));
2184
2185 // skip after somewhere?
2186 return AST::Visibility::create_error ();
2187 }
2188
2189 skip_token (RIGHT_PAREN);
2190
2191 return AST::Visibility::create_in_path (std::move (path));
2192 }
2193 default:
2194 add_error (Error (t->get_locus (), "unexpected token %qs in visibility",
2195 t->get_token_description ()));
2196
2197 lexer.skip_token ();
2198 return AST::Visibility::create_error ();
2199 }
2200}
2201
2202// Parses a module - either a bodied module or a module defined in another file.
2203template <typename ManagedTokenSource>
2204std::unique_ptr<AST::Module>
2205Parser<ManagedTokenSource>::parse_module (AST::Visibility vis,
2206 AST::AttrVec outer_attrs)
2207{
2208 Location locus = lexer.peek_token ()->get_locus ();
2209 skip_token (MOD);
2210
2211 const_TokenPtr module_name = expect_token (IDENTIFIER);
2212 if (module_name == nullptr)
2213 {
2214 return nullptr;
2215 }
2216 Identifier name = module_name->get_str ();
2217
2218 const_TokenPtr t = lexer.peek_token ();
2219
2220 switch (t->get_id ())
2221 {
2222 case SEMICOLON:
2223 lexer.skip_token ();
2224
2225 // Construct an external module
2226 return std::unique_ptr<AST::Module> (
2227 new AST::Module (std::move (name), std::move (vis),
2228 std::move (outer_attrs), locus, lexer.get_filename (),
2229 inline_module_stack));
2230 case LEFT_CURLY: {
2231 lexer.skip_token ();
2232
2233 // parse inner attributes
2234 AST::AttrVec inner_attrs = parse_inner_attributes ();
2235
2236 std::string module_path_name
2237 = extract_module_path (inner_attrs, outer_attrs, name);
2238 InlineModuleStackScope scope (*this, std::move (module_path_name));
2239
2240 // parse items
2241 std::vector<std::unique_ptr<AST::Item>> items;
2242 const_TokenPtr tok = lexer.peek_token ();
2243 while (tok->get_id () != RIGHT_CURLY)
2244 {
2245 std::unique_ptr<AST::Item> item = parse_item (false);
2246 if (item == nullptr)
2247 {
2248 Error error (tok->get_locus (),
2249 "failed to parse item in module");
2250 add_error (std::move (error));
2251
2252 return nullptr;
2253 }
2254
2255 items.push_back (std::move (item));
2256
2257 tok = lexer.peek_token ();
2258 }
2259
2260 if (!skip_token (RIGHT_CURLY))
2261 {
2262 // skip somewhere?
2263 return nullptr;
2264 }
2265
2266 return std::unique_ptr<AST::Module> (
2267 new AST::Module (std::move (name), locus, std::move (items),
2268 std::move (vis), std::move (inner_attrs),
2269 std::move (outer_attrs))); // module name?
2270 }
2271 default:
2272 add_error (
2273 Error (t->get_locus (),
2274 "unexpected token %qs in module declaration/definition item",
2275 t->get_token_description ()));
2276
2277 lexer.skip_token ();
2278 return nullptr;
2279 }
2280}
2281
2282// Parses an extern crate declaration (dependency on external crate)
2283template <typename ManagedTokenSource>
2284std::unique_ptr<AST::ExternCrate>
2285Parser<ManagedTokenSource>::parse_extern_crate (AST::Visibility vis,
2286 AST::AttrVec outer_attrs)
2287{
2288 Location locus = lexer.peek_token ()->get_locus ();
2289 if (!skip_token (EXTERN_TOK))
2290 {
2291 skip_after_semicolon ();
2292 return nullptr;
2293 }
2294
2295 if (!skip_token (CRATE))
2296 {
2297 skip_after_semicolon ();
2298 return nullptr;
2299 }
2300
2301 /* parse crate reference name - this has its own syntactical rule in reference
2302 * but seems to not be used elsewhere, so i'm putting it here */
2303 const_TokenPtr crate_name_tok = lexer.peek_token ();
2304 std::string crate_name;
2305
2306 switch (crate_name_tok->get_id ())
2307 {
2308 case IDENTIFIER:
2309 crate_name = crate_name_tok->get_str ();
2310 lexer.skip_token ();
2311 break;
2312 case SELF:
2313 crate_name = "self";
2314 lexer.skip_token ();
2315 break;
2316 default:
2317 add_error (
2318 Error (crate_name_tok->get_locus (),
2319 "expecting crate name (identifier or %<self%>), found %qs",
2320 crate_name_tok->get_token_description ()));
2321
2322 skip_after_semicolon ();
2323 return nullptr;
2324 }
2325
2326 // don't parse as clause if it doesn't exist
2327 if (lexer.peek_token ()->get_id () == SEMICOLON)
2328 {
2329 lexer.skip_token ();
2330
2331 return std::unique_ptr<AST::ExternCrate> (
2332 new AST::ExternCrate (std::move (crate_name), std::move (vis),
2333 std::move (outer_attrs), locus));
2334 }
2335
2336 /* parse as clause - this also has its own syntactical rule in reference and
2337 * also seems to not be used elsewhere, so including here again. */
2338 if (!skip_token (AS))
2339 {
2340 skip_after_semicolon ();
2341 return nullptr;
2342 }
2343
2344 const_TokenPtr as_name_tok = lexer.peek_token ();
2345 std::string as_name;
2346
2347 switch (as_name_tok->get_id ())
2348 {
2349 case IDENTIFIER:
2350 as_name = as_name_tok->get_str ();
2351 lexer.skip_token ();
2352 break;
2353 case UNDERSCORE:
2354 as_name = "_";
2355 lexer.skip_token ();
2356 break;
2357 default:
2358 add_error (
2359 Error (as_name_tok->get_locus (),
2360 "expecting as clause name (identifier or %<_%>), found %qs",
2361 as_name_tok->get_token_description ()));
2362
2363 skip_after_semicolon ();
2364 return nullptr;
2365 }
2366
2367 if (!skip_token (SEMICOLON))
2368 {
2369 skip_after_semicolon ();
2370 return nullptr;
2371 }
2372
2373 return std::unique_ptr<AST::ExternCrate> (
2374 new AST::ExternCrate (std::move (crate_name), std::move (vis),
2375 std::move (outer_attrs), locus, std::move (as_name)));
2376}
2377
2378// Parses a use declaration.
2379template <typename ManagedTokenSource>
2380std::unique_ptr<AST::UseDeclaration>
2381Parser<ManagedTokenSource>::parse_use_decl (AST::Visibility vis,
2382 AST::AttrVec outer_attrs)
2383{
2384 Location locus = lexer.peek_token ()->get_locus ();
2385 if (!skip_token (USE))
2386 {
2387 skip_after_semicolon ();
2388 return nullptr;
2389 }
2390
2391 // parse use tree, which is required
2392 std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
2393 if (use_tree == nullptr)
2394 {
2395 Error error (lexer.peek_token ()->get_locus (),
2396 "could not parse use tree in use declaration");
2397 add_error (std::move (error));
2398
2399 skip_after_semicolon ();
2400 return nullptr;
2401 }
2402
2403 if (!skip_token (SEMICOLON))
2404 {
2405 skip_after_semicolon ();
2406 return nullptr;
2407 }
2408
2409 return std::unique_ptr<AST::UseDeclaration> (
2410 new AST::UseDeclaration (std::move (use_tree), std::move (vis),
2411 std::move (outer_attrs), locus));
2412}
2413
2414// Parses a use tree (which can be recursive and is actually a base class).
2415template <typename ManagedTokenSource>
2416std::unique_ptr<AST::UseTree>
2417Parser<ManagedTokenSource>::parse_use_tree ()
2418{
2419 /* potential syntax definitions in attempt to get algorithm:
2420 * Glob:
2421 * <- SimplePath :: *
2422 * <- :: *
2423 * <- *
2424 * Nested tree thing:
2425 * <- SimplePath :: { COMPLICATED_INNER_TREE_THING }
2426 * <- :: COMPLICATED_INNER_TREE_THING }
2427 * <- { COMPLICATED_INNER_TREE_THING }
2428 * Rebind thing:
2429 * <- SimplePath as IDENTIFIER
2430 * <- SimplePath as _
2431 * <- SimplePath
2432 */
2433
2434 /* current plan of attack: try to parse SimplePath first - if fails, one of
2435 * top two then try parse :: - if fails, one of top two. Next is deciding
2436 * character for top two. */
2437
2438 /* Thus, parsing smaller parts of use tree may require feeding into function
2439 * via parameters (or could handle all in this single function because other
2440 * use tree types aren't recognised as separate in the spec) */
2441
2442 // TODO: I think this function is too complex, probably should split it
2443
2444 Location locus = lexer.peek_token ()->get_locus ();
2445
2446 // bool has_path = false;
2447 AST::SimplePath path = parse_simple_path ();
2448
2449 if (path.is_empty ())
2450 {
2451 // has no path, so must be glob or nested tree UseTree type
2452
2453 bool is_global = false;
2454
2455 // check for global scope resolution operator
2456 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
2457 {
2458 lexer.skip_token ();
2459 is_global = true;
2460 }
2461
2462 const_TokenPtr t = lexer.peek_token ();
2463 switch (t->get_id ())
2464 {
2465 case ASTERISK:
2466 // glob UseTree type
2467 lexer.skip_token ();
2468
2469 if (is_global)
2470 return std::unique_ptr<AST::UseTreeGlob> (
2471 new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL,
2472 AST::SimplePath::create_empty (), locus));
2473 else
2474 return std::unique_ptr<AST::UseTreeGlob> (
2475 new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH,
2476 AST::SimplePath::create_empty (), locus));
2477 case LEFT_CURLY: {
2478 // nested tree UseTree type
2479 lexer.skip_token ();
2480
2481 std::vector<std::unique_ptr<AST::UseTree>> use_trees;
2482
2483 const_TokenPtr t = lexer.peek_token ();
2484 while (t->get_id () != RIGHT_CURLY)
2485 {
2486 std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
2487 if (use_tree == nullptr)
2488 {
2489 break;
2490 }
2491
2492 use_trees.push_back (std::move (use_tree));
2493
2494 if (lexer.peek_token ()->get_id () != COMMA)
2495 break;
2496
2497 lexer.skip_token ();
2498 t = lexer.peek_token ();
2499 }
2500
2501 // skip end curly delimiter
2502 if (!skip_token (RIGHT_CURLY))
2503 {
2504 // skip after somewhere?
2505 return nullptr;
2506 }
2507
2508 if (is_global)
2509 return std::unique_ptr<AST::UseTreeList> (
2510 new AST::UseTreeList (AST::UseTreeList::GLOBAL,
2511 AST::SimplePath::create_empty (),
2512 std::move (use_trees), locus));
2513 else
2514 return std::unique_ptr<AST::UseTreeList> (
2515 new AST::UseTreeList (AST::UseTreeList::NO_PATH,
2516 AST::SimplePath::create_empty (),
2517 std::move (use_trees), locus));
2518 }
2519 case AS:
2520 // this is not allowed
2521 add_error (Error (
2522 t->get_locus (),
2523 "use declaration with rebind %<as%> requires a valid simple path - "
2524 "none found"));
2525
2526 skip_after_semicolon ();
2527 return nullptr;
2528 default:
2529 add_error (Error (t->get_locus (),
2530 "unexpected token %qs in use tree with "
2531 "no valid simple path (i.e. list"
2532 " or glob use tree)",
2533 t->get_token_description ()));
2534
2535 skip_after_semicolon ();
2536 return nullptr;
2537 }
2538 }
2539 else
2540 {
2541 /* Due to aforementioned implementation issues, the trailing :: token is
2542 * consumed by the path, so it can not be used as a disambiguator.
2543 * NOPE, not true anymore - TODO what are the consequences of this? */
2544
2545 const_TokenPtr t = lexer.peek_token ();
2546 switch (t->get_id ())
2547 {
2548 case ASTERISK:
2549 // glob UseTree type
2550 lexer.skip_token ();
2551
2552 return std::unique_ptr<AST::UseTreeGlob> (
2553 new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED,
2554 std::move (path), locus));
2555 case LEFT_CURLY: {
2556 // nested tree UseTree type
2557 lexer.skip_token ();
2558
2559 std::vector<std::unique_ptr<AST::UseTree>> use_trees;
2560
2561 // TODO: think of better control structure
2562 const_TokenPtr t = lexer.peek_token ();
2563 while (t->get_id () != RIGHT_CURLY)
2564 {
2565 std::unique_ptr<AST::UseTree> use_tree = parse_use_tree ();
2566 if (use_tree == nullptr)
2567 {
2568 break;
2569 }
2570
2571 use_trees.push_back (std::move (use_tree));
2572
2573 if (lexer.peek_token ()->get_id () != COMMA)
2574 break;
2575
2576 lexer.skip_token ();
2577 t = lexer.peek_token ();
2578 }
2579
2580 // skip end curly delimiter
2581 if (!skip_token (RIGHT_CURLY))
2582 {
2583 // skip after somewhere?
2584 return nullptr;
2585 }
2586
2587 return std::unique_ptr<AST::UseTreeList> (
2588 new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED,
2589 std::move (path), std::move (use_trees),
2590 locus));
2591 }
2592 case AS: {
2593 // rebind UseTree type
2594 lexer.skip_token ();
2595
2596 const_TokenPtr t = lexer.peek_token ();
2597 switch (t->get_id ())
2598 {
2599 case IDENTIFIER:
2600 // skip lexer token
2601 lexer.skip_token ();
2602
2603 return std::unique_ptr<AST::UseTreeRebind> (
2604 new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER,
2605 std::move (path), locus,
2606 t->get_str ()));
2607 case UNDERSCORE:
2608 // skip lexer token
2609 lexer.skip_token ();
2610
2611 return std::unique_ptr<AST::UseTreeRebind> (
2612 new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD,
2613 std::move (path), locus, "_"));
2614 default:
2615 add_error (Error (
2616 t->get_locus (),
2617 "unexpected token %qs in use tree with as clause - expected "
2618 "identifier or %<_%>",
2619 t->get_token_description ()));
2620
2621 skip_after_semicolon ();
2622 return nullptr;
2623 }
2624 }
2625 case SEMICOLON:
2626 // rebind UseTree type without rebinding - path only
2627
2628 // don't skip semicolon - handled in parse_use_tree
2629 // lexer.skip_token();
2630
2631 return std::unique_ptr<AST::UseTreeRebind> (
2632 new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path),
2633 locus));
2634 case COMMA:
2635 case RIGHT_CURLY:
2636 // this may occur in recursive calls - assume it is ok and ignore it
2637 return std::unique_ptr<AST::UseTreeRebind> (
2638 new AST::UseTreeRebind (AST::UseTreeRebind::NONE, std::move (path),
2639 locus));
2640 default:
2641 add_error (Error (t->get_locus (),
2642 "unexpected token %qs in use tree with valid path",
2643 t->get_token_description ()));
2644
2645 // skip_after_semicolon();
2646 return nullptr;
2647 }
2648 }
2649}
2650
2651// Parses a function (not a method).
2652template <typename ManagedTokenSource>
2653std::unique_ptr<AST::Function>
2654Parser<ManagedTokenSource>::parse_function (AST::Visibility vis,
2655 AST::AttrVec outer_attrs)
2656{
2657 Location locus = lexer.peek_token ()->get_locus ();
2658 // Get qualifiers for function if they exist
2659 AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
2660
2661 skip_token (FN_TOK);
2662
2663 // Save function name token
2664 const_TokenPtr function_name_tok = expect_token (IDENTIFIER);
2665 if (function_name_tok == nullptr)
2666 {
2667 skip_after_next_block ();
2668 return nullptr;
2669 }
2670 Identifier function_name = function_name_tok->get_str ();
2671
2672 // parse generic params - if exist
2673 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
2674 = parse_generic_params_in_angles ();
2675
2676 if (!skip_token (LEFT_PAREN))
2677 {
2678 Error error (lexer.peek_token ()->get_locus (),
2679 "function declaration missing opening parentheses before "
2680 "parameter list");
2681 add_error (std::move (error));
2682
2683 skip_after_next_block ();
2684 return nullptr;
2685 }
2686
2687 // parse function parameters (only if next token isn't right paren)
2688 std::vector<AST::FunctionParam> function_params;
2689 if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
2690 function_params
2691 = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
2692
2693 if (!skip_token (RIGHT_PAREN))
2694 {
2695 Error error (lexer.peek_token ()->get_locus (),
2696 "function declaration missing closing parentheses after "
2697 "parameter list");
2698 add_error (std::move (error));
2699
2700 skip_after_next_block ();
2701 return nullptr;
2702 }
2703
2704 // parse function return type - if exists
2705 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
2706
2707 // parse where clause - if exists
2708 AST::WhereClause where_clause = parse_where_clause ();
2709
2710 // parse block expression
2711 std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
2712
2713 return std::unique_ptr<AST::Function> (
2714 new AST::Function (std::move (function_name), std::move (qualifiers),
2715 std::move (generic_params), std::move (function_params),
2716 std::move (return_type), std::move (where_clause),
2717 std::move (block_expr), std::move (vis),
2718 std::move (outer_attrs), locus));
2719}
2720
2721// Parses function or method qualifiers (i.e. const, unsafe, and extern).
2722template <typename ManagedTokenSource>
2723AST::FunctionQualifiers
2724Parser<ManagedTokenSource>::parse_function_qualifiers ()
2725{
2726 AsyncConstStatus const_status = NONE;
2727 bool has_unsafe = false;
2728 bool has_extern = false;
2729 std::string abi;
2730
2731 // Check in order of const, unsafe, then extern
2732 const_TokenPtr t = lexer.peek_token ();
2733 Location locus = t->get_locus ();
2734 switch (t->get_id ())
2735 {
2736 case CONST:
2737 lexer.skip_token ();
2738 const_status = CONST_FN;
2739 break;
2740 case ASYNC:
2741 lexer.skip_token ();
2742 const_status = ASYNC_FN;
2743 break;
2744 default:
2745 // const status is still none
2746 break;
2747 }
2748
2749 if (lexer.peek_token ()->get_id () == UNSAFE)
2750 {
2751 lexer.skip_token ();
2752 has_unsafe = true;
2753 }
2754
2755 if (lexer.peek_token ()->get_id () == EXTERN_TOK)
2756 {
2757 lexer.skip_token ();
2758 has_extern = true;
2759
2760 // detect optional abi name
2761 const_TokenPtr next_tok = lexer.peek_token ();
2762 if (next_tok->get_id () == STRING_LITERAL)
2763 {
2764 lexer.skip_token ();
2765 abi = next_tok->get_str ();
2766 }
2767 }
2768
2769 return AST::FunctionQualifiers (locus, const_status, has_unsafe, has_extern,
2770 std::move (abi));
2771}
2772
2773// Parses generic (lifetime or type) params inside angle brackets (optional).
2774template <typename ManagedTokenSource>
2775std::vector<std::unique_ptr<AST::GenericParam>>
2776Parser<ManagedTokenSource>::parse_generic_params_in_angles ()
2777{
2778 if (lexer.peek_token ()->get_id () != LEFT_ANGLE)
2779 {
2780 // seems to be no generic params, so exit with empty vector
2781 return std::vector<std::unique_ptr<AST::GenericParam>> ();
2782 }
2783 lexer.skip_token ();
2784
2785 // DEBUG:
2786 rust_debug ("skipped left angle in generic param");
2787
2788 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
2789 = parse_generic_params (is_right_angle_tok);
2790
2791 // DEBUG:
2792 rust_debug ("finished parsing actual generic params (i.e. inside angles)");
2793
2794 if (!skip_generics_right_angle ())
2795 {
2796 // DEBUG
2797 rust_debug ("failed to skip generics right angle - returning empty "
2798 "generic params");
2799
2800 return std::vector<std::unique_ptr<AST::GenericParam>> ();
2801 }
2802
2803 return generic_params;
2804}
2805
2806template <typename ManagedTokenSource>
2807template <typename EndTokenPred>
2808std::unique_ptr<AST::GenericParam>
2809Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
2810{
2811 auto token = lexer.peek_token ();
2812 auto outer_attrs = parse_outer_attribute ();
2813 std::unique_ptr<AST::GenericParam> param;
2814
2815 switch (token->get_id ())
2816 {
2817 case LIFETIME: {
2818 auto lifetime = parse_lifetime ();
2819 if (lifetime.is_error ())
2820 {
2821 rust_error_at (
2822 token->get_locus (),
2823 "failed to parse lifetime in generic parameter list");
2824 return nullptr;
2825 }
2826
2827 std::vector<AST::Lifetime> lifetime_bounds;
2828 if (lexer.peek_token ()->get_id () == COLON)
2829 {
2830 lexer.skip_token ();
2831 // parse required bounds
2832 lifetime_bounds
2833 = parse_lifetime_bounds ([is_end_token] (TokenId id) {
2834 return is_end_token (id) || id == COMMA;
2835 });
2836 }
2837
2838 param = std::unique_ptr<AST::LifetimeParam> (new AST::LifetimeParam (
2839 std::move (lifetime), std::move (lifetime_bounds),
2840 std::move (outer_attrs), token->get_locus ()));
2841 break;
2842 }
2843 case IDENTIFIER: {
2844 auto type_ident = token->get_str ();
2845 lexer.skip_token ();
2846
2847 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
2848 if (lexer.peek_token ()->get_id () == COLON)
2849 {
2850 lexer.skip_token ();
2851
2852 // parse optional type param bounds
2853 type_param_bounds = parse_type_param_bounds ();
2854 }
2855
2856 std::unique_ptr<AST::Type> type = nullptr;
2857 if (lexer.peek_token ()->get_id () == EQUAL)
2858 {
2859 lexer.skip_token ();
2860
2861 // parse required type
2862 type = parse_type ();
2863 if (!type)
2864 {
2865 rust_error_at (
2866 lexer.peek_token ()->get_locus (),
2867 "failed to parse type in type param in generic params");
2868 return nullptr;
2869 }
2870 }
2871
2872 param = std::unique_ptr<AST::TypeParam> (
2873 new AST::TypeParam (std::move (type_ident), token->get_locus (),
2874 std::move (type_param_bounds), std::move (type),
2875 std::move (outer_attrs)));
2876 break;
2877 }
2878 case CONST: {
2879 lexer.skip_token ();
2880
2881 auto name_token = expect_token (IDENTIFIER);
2882
2883 if (!name_token || !expect_token (COLON))
2884 return nullptr;
2885
2886 auto type = parse_type ();
2887 if (!type)
2888 return nullptr;
2889
2890 // optional default value
2891 auto default_expr = AST::GenericArg::create_error ();
2892 if (lexer.peek_token ()->get_id () == EQUAL)
2893 {
2894 lexer.skip_token ();
2895 auto tok = lexer.peek_token ();
2896 default_expr = parse_generic_arg ();
2897
2898 if (default_expr.is_error ())
2899 rust_error_at (tok->get_locus (),
2900 "invalid token for start of default value for "
2901 "const generic parameter: expected %<block%>, "
2902 "%<identifier%> or %<literal%>, got %qs",
2903 token_id_to_str (tok->get_id ()));
2904
2905 // At this point, we *know* that we are parsing a const
2906 // expression
2907 if (default_expr.get_kind () == AST::GenericArg::Kind::Either)
2908 default_expr = default_expr.disambiguate_to_const ();
2909 }
2910
2911 param = std::unique_ptr<AST::ConstGenericParam> (
2912 new AST::ConstGenericParam (name_token->get_str (), std::move (type),
2913 default_expr, std::move (outer_attrs),
2914 token->get_locus ()));
2915
2916 break;
2917 }
2918 default:
2919 // FIXME: Can we clean this last call with a method call?
2920 rust_error_at (token->get_locus (),
2921 "unexpected token when parsing generic parameters: %qs",
2922 token->get_str ().c_str ());
2923 return nullptr;
2924 }
2925
2926 return param;
2927}
2928
2929/* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost
2930 * always parse_generic_params_in_angles is what is wanted. */
2931template <typename ManagedTokenSource>
2932template <typename EndTokenPred>
2933std::vector<std::unique_ptr<AST::GenericParam>>
2934Parser<ManagedTokenSource>::parse_generic_params (EndTokenPred is_end_token)
2935{
2936 std::vector<std::unique_ptr<AST::GenericParam>> generic_params;
2937
2938 /* can't parse lifetime and type params separately due to lookahead issues
2939 * thus, parse them all here */
2940
2941 /* HACK: used to retain attribute data if a lifetime param is tentatively
2942 * parsed but it turns out to be type param */
2943 AST::Attribute parsed_outer_attr = AST::Attribute::create_empty ();
2944
2945 // Did we parse a generic type param yet
2946 auto type_seen = false;
2947 // Did the user write a lifetime parameter after a type one
2948 auto order_error = false;
2949
2950 // parse lifetime params
2951 while (!is_end_token (lexer.peek_token ()->get_id ()))
2952 {
2953 auto param = parse_generic_param (is_end_token);
2954 if (param)
2955 {
2956 // TODO: Handle `Const` here as well if necessary
2957 if (param->get_kind () == AST::GenericParam::Kind::Type)
2958 type_seen = true;
2959 else if (param->get_kind () == AST::GenericParam::Kind::Lifetime
2960 && type_seen)
2961 order_error = true;
2962
2963 generic_params.emplace_back (std::move (param));
2964 maybe_skip_token (COMMA);
2965 }
2966 }
2967
2968 // FIXME: Add reordering hint
2969 if (order_error)
2970 rust_error_at (generic_params.front ()->get_locus (),
2971 "invalid order for generic parameters: lifetimes should "
2972 "always come before types");
2973
2974 generic_params.shrink_to_fit ();
2975 return generic_params;
2976}
2977
2978/* Parses lifetime generic parameters (pointers). Will also consume any
2979 * trailing comma. No extra checks for end token. */
2980template <typename ManagedTokenSource>
2981std::vector<std::unique_ptr<AST::LifetimeParam>>
2982Parser<ManagedTokenSource>::parse_lifetime_params ()
2983{
2984 std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
2985
2986 while (lexer.peek_token ()->get_id () != END_OF_FILE)
2987 {
2988 AST::LifetimeParam lifetime_param = parse_lifetime_param ();
2989
2990 if (lifetime_param.is_error ())
2991 {
2992 // can't treat as error as only way to get out with trailing comma
2993 break;
2994 }
2995
2996 lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> (
2997 new AST::LifetimeParam (std::move (lifetime_param))));
2998
2999 if (lexer.peek_token ()->get_id () != COMMA)
3000 break;
3001
3002 // skip commas, including trailing commas
3003 lexer.skip_token ();
3004 }
3005
3006 lifetime_params.shrink_to_fit ();
3007
3008 return lifetime_params;
3009}
3010
3011/* Parses lifetime generic parameters (pointers). Will also consume any
3012 * trailing comma. Has extra is_end_token predicate checking. */
3013template <typename ManagedTokenSource>
3014template <typename EndTokenPred>
3015std::vector<std::unique_ptr<AST::LifetimeParam>>
3016Parser<ManagedTokenSource>::parse_lifetime_params (EndTokenPred is_end_token)
3017{
3018 std::vector<std::unique_ptr<AST::LifetimeParam>> lifetime_params;
3019
3020 // if end_token is not specified, it defaults to EOF, so should work fine
3021 while (!is_end_token (lexer.peek_token ()->get_id ()))
3022 {
3023 AST::LifetimeParam lifetime_param = parse_lifetime_param ();
3024
3025 if (lifetime_param.is_error ())
3026 {
3027 /* TODO: is it worth throwing away all lifetime params just because
3028 * one failed? */
3029 Error error (lexer.peek_token ()->get_locus (),
3030 "failed to parse lifetime param in lifetime params");
3031 add_error (std::move (error));
3032
3033 return {};
3034 }
3035
3036 lifetime_params.push_back (std::unique_ptr<AST::LifetimeParam> (
3037 new AST::LifetimeParam (std::move (lifetime_param))));
3038
3039 if (lexer.peek_token ()->get_id () != COMMA)
3040 break;
3041
3042 // skip commas, including trailing commas
3043 lexer.skip_token ();
3044 }
3045
3046 lifetime_params.shrink_to_fit ();
3047
3048 return lifetime_params;
3049}
3050
3051/* Parses lifetime generic parameters (objects). Will also consume any
3052 * trailing comma. No extra checks for end token.
3053 * TODO: is this best solution? implements most of the same algorithm. */
3054template <typename ManagedTokenSource>
3055std::vector<AST::LifetimeParam>
3056Parser<ManagedTokenSource>::parse_lifetime_params_objs ()
3057{
3058 std::vector<AST::LifetimeParam> lifetime_params;
3059
3060 // bad control structure as end token cannot be guaranteed
3061 while (true)
3062 {
3063 AST::LifetimeParam lifetime_param = parse_lifetime_param ();
3064
3065 if (lifetime_param.is_error ())
3066 {
3067 // not an error as only way to exit if trailing comma
3068 break;
3069 }
3070
3071 lifetime_params.push_back (std::move (lifetime_param));
3072
3073 if (lexer.peek_token ()->get_id () != COMMA)
3074 break;
3075
3076 // skip commas, including trailing commas
3077 lexer.skip_token ();
3078 }
3079
3080 lifetime_params.shrink_to_fit ();
3081
3082 return lifetime_params;
3083}
3084
3085/* Parses lifetime generic parameters (objects). Will also consume any
3086 * trailing comma. Has extra is_end_token predicate checking.
3087 * TODO: is this best solution? implements most of the same algorithm. */
3088template <typename ManagedTokenSource>
3089template <typename EndTokenPred>
3090std::vector<AST::LifetimeParam>
3091Parser<ManagedTokenSource>::parse_lifetime_params_objs (
3092 EndTokenPred is_end_token)
3093{
3094 std::vector<AST::LifetimeParam> lifetime_params;
3095
3096 while (!is_end_token (lexer.peek_token ()->get_id ()))
3097 {
3098 AST::LifetimeParam lifetime_param = parse_lifetime_param ();
3099
3100 if (lifetime_param.is_error ())
3101 {
3102 /* TODO: is it worth throwing away all lifetime params just because
3103 * one failed? */
3104 Error error (lexer.peek_token ()->get_locus (),
3105 "failed to parse lifetime param in lifetime params");
3106 add_error (std::move (error));
3107
3108 return {};
3109 }
3110
3111 lifetime_params.push_back (std::move (lifetime_param));
3112
3113 if (lexer.peek_token ()->get_id () != COMMA)
3114 break;
3115
3116 // skip commas, including trailing commas
3117 lexer.skip_token ();
3118 }
3119
3120 lifetime_params.shrink_to_fit ();
3121
3122 return lifetime_params;
3123}
3124
3125/* Parses a sequence of a certain grammar rule in object form (not pointer or
3126 * smart pointer), delimited by commas and ending when 'is_end_token' is
3127 * satisfied (templated). Will also consume any trailing comma.
3128 * FIXME: this cannot be used due to member function pointer problems (i.e.
3129 * parsing_function cannot be specified properly) */
3130template <typename ManagedTokenSource>
3131template <typename ParseFunction, typename EndTokenPred>
3132auto
3133Parser<ManagedTokenSource>::parse_non_ptr_sequence (
3134 ParseFunction parsing_function, EndTokenPred is_end_token,
3135 std::string error_msg) -> std::vector<decltype (parsing_function ())>
3136{
3137 std::vector<decltype (parsing_function ())> params;
3138
3139 while (!is_end_token (lexer.peek_token ()->get_id ()))
3140 {
3141 auto param = parsing_function ();
3142
3143 if (param.is_error ())
3144 {
3145 // TODO: is it worth throwing away all params just because one
3146 // failed?
3147 Error error (lexer.peek_token ()->get_locus (),
3148 std::move (error_msg));
3149 add_error (std::move (error));
3150
3151 return {};
3152 }
3153
3154 params.push_back (std::move (param));
3155
3156 if (lexer.peek_token ()->get_id () != COMMA)
3157 break;
3158
3159 // skip commas, including trailing commas
3160 lexer.skip_token ();
3161 }
3162
3163 params.shrink_to_fit ();
3164
3165 return params;
3166}
3167
3168/* Parses a single lifetime generic parameter (not including comma). */
3169template <typename ManagedTokenSource>
3170AST::LifetimeParam
3171Parser<ManagedTokenSource>::parse_lifetime_param ()
3172{
3173 // parse outer attribute, which is optional and may not exist
3174 AST::Attribute outer_attr = parse_outer_attribute ();
3175
3176 // save lifetime token - required
3177 const_TokenPtr lifetime_tok = lexer.peek_token ();
3178 if (lifetime_tok->get_id () != LIFETIME)
3179 {
3180 // if lifetime is missing, must not be a lifetime param, so return null
3181 return AST::LifetimeParam::create_error ();
3182 }
3183 lexer.skip_token ();
3184 /* TODO: does this always create a named lifetime? or can a different type
3185 * be made? */
3186 AST::Lifetime lifetime (AST::Lifetime::NAMED, lifetime_tok->get_str (),
3187 lifetime_tok->get_locus ());
3188
3189 // parse lifetime bounds, if it exists
3190 std::vector<AST::Lifetime> lifetime_bounds;
3191 if (lexer.peek_token ()->get_id () == COLON)
3192 {
3193 // parse lifetime bounds
3194 lifetime_bounds = parse_lifetime_bounds ();
3195 // TODO: have end token passed in?
3196 }
3197
3198 return AST::LifetimeParam (std::move (lifetime), std::move (lifetime_bounds),
3199 std::move (outer_attr),
3200 lifetime_tok->get_locus ());
3201}
3202
3203// Parses type generic parameters. Will also consume any trailing comma.
3204template <typename ManagedTokenSource>
3205std::vector<std::unique_ptr<AST::TypeParam>>
3206Parser<ManagedTokenSource>::parse_type_params ()
3207{
3208 std::vector<std::unique_ptr<AST::TypeParam>> type_params;
3209
3210 // infinite loop with break on failure as no info on ending token
3211 while (true)
3212 {
3213 std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
3214
3215 if (type_param == nullptr)
3216 {
3217 // break if fails to parse
3218 break;
3219 }
3220
3221 type_params.push_back (std::move (type_param));
3222
3223 if (lexer.peek_token ()->get_id () != COMMA)
3224 break;
3225
3226 // skip commas, including trailing commas
3227 lexer.skip_token ();
3228 }
3229
3230 type_params.shrink_to_fit ();
3231 return type_params;
3232}
3233
3234// Parses type generic parameters. Will also consume any trailing comma.
3235template <typename ManagedTokenSource>
3236template <typename EndTokenPred>
3237std::vector<std::unique_ptr<AST::TypeParam>>
3238Parser<ManagedTokenSource>::parse_type_params (EndTokenPred is_end_token)
3239{
3240 std::vector<std::unique_ptr<AST::TypeParam>> type_params;
3241
3242 while (!is_end_token (lexer.peek_token ()->get_id ()))
3243 {
3244 std::unique_ptr<AST::TypeParam> type_param = parse_type_param ();
3245
3246 if (type_param == nullptr)
3247 {
3248 Error error (lexer.peek_token ()->get_locus (),
3249 "failed to parse type param in type params");
3250 add_error (std::move (error));
3251
3252 return {};
3253 }
3254
3255 type_params.push_back (std::move (type_param));
3256
3257 if (lexer.peek_token ()->get_id () != COMMA)
3258 break;
3259
3260 // skip commas, including trailing commas
3261 lexer.skip_token ();
3262 }
3263
3264 type_params.shrink_to_fit ();
3265 return type_params;
3266 /* TODO: this shares most code with parse_lifetime_params - good place to
3267 * use template (i.e. parse_non_ptr_sequence if doable) */
3268}
3269
3270/* Parses a single type (generic) parameter, not including commas. May change
3271 * to return value. */
3272template <typename ManagedTokenSource>
3273std::unique_ptr<AST::TypeParam>
3274Parser<ManagedTokenSource>::parse_type_param ()
3275{
3276 // parse outer attribute, which is optional and may not exist
3277 AST::Attribute outer_attr = parse_outer_attribute ();
3278
3279 const_TokenPtr identifier_tok = lexer.peek_token ();
3280 if (identifier_tok->get_id () != IDENTIFIER)
3281 {
3282 // return null as type param can't exist without this required
3283 // identifier
3284 return nullptr;
3285 }
3286 // TODO: create identifier from identifier token
3287 Identifier ident = identifier_tok->get_str ();
3288 lexer.skip_token ();
3289
3290 // parse type param bounds (if they exist)
3291 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3292 if (lexer.peek_token ()->get_id () == COLON)
3293 {
3294 lexer.skip_token ();
3295
3296 // parse type param bounds, which may or may not exist
3297 type_param_bounds = parse_type_param_bounds ();
3298 }
3299
3300 // parse type (if it exists)
3301 std::unique_ptr<AST::Type> type = nullptr;
3302 if (lexer.peek_token ()->get_id () == EQUAL)
3303 {
3304 lexer.skip_token ();
3305
3306 // parse type (now required)
3307 type = parse_type ();
3308 if (type == nullptr)
3309 {
3310 Error error (lexer.peek_token ()->get_locus (),
3311 "failed to parse type in type param");
3312 add_error (std::move (error));
3313
3314 return nullptr;
3315 }
3316 }
3317
3318 return std::unique_ptr<AST::TypeParam> (
3319 new AST::TypeParam (std::move (ident), identifier_tok->get_locus (),
3320 std::move (type_param_bounds), std::move (type),
3321 std::move (outer_attr)));
3322}
3323
3324/* Parses regular (i.e. non-generic) parameters in functions or methods. Also
3325 * has end token handling. */
3326template <typename ManagedTokenSource>
3327template <typename EndTokenPred>
3328std::vector<AST::FunctionParam>
3329Parser<ManagedTokenSource>::parse_function_params (EndTokenPred is_end_token)
3330{
3331 std::vector<AST::FunctionParam> params;
3332
3333 if (is_end_token (lexer.peek_token ()->get_id ()))
3334 return params;
3335
3336 AST::FunctionParam initial_param = parse_function_param ();
3337
3338 // Return empty parameter list if no parameter there
3339 if (initial_param.is_error ())
3340 {
3341 // TODO: is this an error?
3342 return params;
3343 }
3344
3345 params.push_back (std::move (initial_param));
3346
3347 // maybe think of a better control structure here - do-while with an initial
3348 // error state? basically, loop through parameter list until can't find any
3349 // more params
3350 const_TokenPtr t = lexer.peek_token ();
3351 while (t->get_id () == COMMA)
3352 {
3353 // skip comma if applies
3354 lexer.skip_token ();
3355
3356 // TODO: strictly speaking, shouldn't there be no trailing comma?
3357 if (is_end_token (lexer.peek_token ()->get_id ()))
3358 break;
3359
3360 // now, as right paren would break, function param is required
3361 AST::FunctionParam param = parse_function_param ();
3362 if (param.is_error ())
3363 {
3364 Error error (lexer.peek_token ()->get_locus (),
3365 "failed to parse function param (in function params)");
3366 add_error (std::move (error));
3367
3368 // skip somewhere?
3369 return std::vector<AST::FunctionParam> ();
3370 }
3371
3372 params.push_back (std::move (param));
3373
3374 t = lexer.peek_token ();
3375 }
3376
3377 params.shrink_to_fit ();
3378 return params;
3379}
3380
3381/* Parses a single regular (i.e. non-generic) parameter in a function or
3382 * method, i.e. the "name: type" bit. Also handles it not existing. */
3383template <typename ManagedTokenSource>
3384AST::FunctionParam
3385Parser<ManagedTokenSource>::parse_function_param ()
3386{
3387 // parse outer attributes if they exist
3388 AST::AttrVec outer_attrs = parse_outer_attributes ();
3389
3390 // TODO: should saved location be at start of outer attributes or pattern?
3391 Location locus = lexer.peek_token ()->get_locus ();
3392 std::unique_ptr<AST::Pattern> param_pattern = parse_pattern ();
3393
3394 // create error function param if it doesn't exist
3395 if (param_pattern == nullptr)
3396 {
3397 // skip after something
3398 return AST::FunctionParam::create_error ();
3399 }
3400
3401 if (!skip_token (COLON))
3402 {
3403 // skip after something
3404 return AST::FunctionParam::create_error ();
3405 }
3406
3407 std::unique_ptr<AST::Type> param_type = parse_type ();
3408 if (param_type == nullptr)
3409 {
3410 // skip?
3411 return AST::FunctionParam::create_error ();
3412 }
3413
3414 return AST::FunctionParam (std::move (param_pattern), std::move (param_type),
3415 std::move (outer_attrs), locus);
3416}
3417
3418/* Parses a function or method return type syntactical construction. Also
3419 * handles a function return type not existing. */
3420template <typename ManagedTokenSource>
3421std::unique_ptr<AST::Type>
3422Parser<ManagedTokenSource>::parse_function_return_type ()
3423{
3424 if (lexer.peek_token ()->get_id () != RETURN_TYPE)
3425 return nullptr;
3426
3427 // skip return type, as it now obviously exists
3428 lexer.skip_token ();
3429
3430 std::unique_ptr<AST::Type> type = parse_type ();
3431
3432 return type;
3433}
3434
3435/* Parses a "where clause" (in a function, struct, method, etc.). Also handles
3436 * a where clause not existing, in which it will return
3437 * WhereClause::create_empty(), which can be checked via
3438 * WhereClause::is_empty(). */
3439template <typename ManagedTokenSource>
3440AST::WhereClause
3441Parser<ManagedTokenSource>::parse_where_clause ()
3442{
3443 const_TokenPtr where_tok = lexer.peek_token ();
3444 if (where_tok->get_id () != WHERE)
3445 {
3446 // where clause doesn't exist, so create empty one
3447 return AST::WhereClause::create_empty ();
3448 }
3449
3450 lexer.skip_token ();
3451
3452 /* parse where clause items - this is not a separate rule in the reference
3453 * so won't be here */
3454 std::vector<std::unique_ptr<AST::WhereClauseItem>> where_clause_items;
3455
3456 /* HACK: where clauses end with a right curly or semicolon or equals in all
3457 * uses currently */
3458 const_TokenPtr t = lexer.peek_token ();
3459 while (t->get_id () != LEFT_CURLY && t->get_id () != SEMICOLON
3460 && t->get_id () != EQUAL)
3461 {
3462 std::unique_ptr<AST::WhereClauseItem> where_clause_item
3463 = parse_where_clause_item ();
3464
3465 if (where_clause_item == nullptr)
3466 {
3467 Error error (t->get_locus (), "failed to parse where clause item");
3468 add_error (std::move (error));
3469
3470 return AST::WhereClause::create_empty ();
3471 }
3472
3473 where_clause_items.push_back (std::move (where_clause_item));
3474
3475 // also skip comma if it exists
3476 if (lexer.peek_token ()->get_id () != COMMA)
3477 break;
3478
3479 lexer.skip_token ();
3480 t = lexer.peek_token ();
3481 }
3482
3483 where_clause_items.shrink_to_fit ();
3484 return AST::WhereClause (std::move (where_clause_items));
3485}
3486
3487/* Parses a where clause item (lifetime or type bound). Does not parse any
3488 * commas. */
3489template <typename ManagedTokenSource>
3490std::unique_ptr<AST::WhereClauseItem>
3491Parser<ManagedTokenSource>::parse_where_clause_item ()
3492{
3493 // shitty cheat way of determining lifetime or type bound - test for
3494 // lifetime
3495 const_TokenPtr t = lexer.peek_token ();
3496
3497 if (t->get_id () == LIFETIME)
3498 return parse_lifetime_where_clause_item ();
3499 else
3500 return parse_type_bound_where_clause_item ();
3501}
3502
3503// Parses a lifetime where clause item.
3504template <typename ManagedTokenSource>
3505std::unique_ptr<AST::LifetimeWhereClauseItem>
3506Parser<ManagedTokenSource>::parse_lifetime_where_clause_item ()
3507{
3508 AST::Lifetime lifetime = parse_lifetime ();
3509 if (lifetime.is_error ())
3510 {
3511 // TODO: error here?
3512 return nullptr;
3513 }
3514
3515 if (!skip_token (COLON))
3516 {
3517 // TODO: skip after somewhere
3518 return nullptr;
3519 }
3520
3521 std::vector<AST::Lifetime> lifetime_bounds = parse_lifetime_bounds ();
3522 // TODO: have end token passed in?
3523
3524 Location locus = lifetime.get_locus ();
3525
3526 return std::unique_ptr<AST::LifetimeWhereClauseItem> (
3527 new AST::LifetimeWhereClauseItem (std::move (lifetime),
3528 std::move (lifetime_bounds), locus));
3529}
3530
3531// Parses a type bound where clause item.
3532template <typename ManagedTokenSource>
3533std::unique_ptr<AST::TypeBoundWhereClauseItem>
3534Parser<ManagedTokenSource>::parse_type_bound_where_clause_item ()
3535{
3536 // parse for lifetimes, if it exists
3537 std::vector<AST::LifetimeParam> for_lifetimes;
3538 if (lexer.peek_token ()->get_id () == FOR)
3539 for_lifetimes = parse_for_lifetimes ();
3540
3541 std::unique_ptr<AST::Type> type = parse_type ();
3542 if (type == nullptr)
3543 {
3544 return nullptr;
3545 }
3546
3547 if (!skip_token (COLON))
3548 {
3549 // TODO: skip after somewhere
3550 return nullptr;
3551 }
3552
3553 // parse type param bounds if they exist
3554 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds
3555 = parse_type_param_bounds ();
3556
3557 Location locus = lexer.peek_token ()->get_locus ();
3558
3559 return std::unique_ptr<AST::TypeBoundWhereClauseItem> (
3560 new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes),
3561 std::move (type),
3562 std::move (type_param_bounds), locus));
3563}
3564
3565// Parses a for lifetimes clause, including the for keyword and angle
3566// brackets.
3567template <typename ManagedTokenSource>
3568std::vector<AST::LifetimeParam>
3569Parser<ManagedTokenSource>::parse_for_lifetimes ()
3570{
3571 std::vector<AST::LifetimeParam> params;
3572
3573 if (!skip_token (FOR))
3574 {
3575 // skip after somewhere?
3576 return params;
3577 }
3578
3579 if (!skip_token (LEFT_ANGLE))
3580 {
3581 // skip after somewhere?
3582 return params;
3583 }
3584
3585 /* cannot specify end token due to parsing problems with '>' tokens being
3586 * nested */
3587 params = parse_lifetime_params_objs (is_right_angle_tok);
3588
3589 if (!skip_generics_right_angle ())
3590 {
3591 // DEBUG
3592 rust_debug ("failed to skip generics right angle after (supposedly) "
3593 "finished parsing where clause items");
3594 // ok, well this gets called.
3595
3596 // skip after somewhere?
3597 return params;
3598 }
3599
3600 return params;
3601}
3602
3603// Parses type parameter bounds in where clause or generic arguments.
3604template <typename ManagedTokenSource>
3605std::vector<std::unique_ptr<AST::TypeParamBound>>
3606Parser<ManagedTokenSource>::parse_type_param_bounds ()
3607{
3608 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3609
3610 std::unique_ptr<AST::TypeParamBound> initial_bound
3611 = parse_type_param_bound ();
3612
3613 // quick exit if null
3614 if (initial_bound == nullptr)
3615 {
3616 /* error? type param bounds must have at least one term, but are bounds
3617 * optional? */
3618 return type_param_bounds;
3619 }
3620 type_param_bounds.push_back (std::move (initial_bound));
3621
3622 while (lexer.peek_token ()->get_id () == PLUS)
3623 {
3624 lexer.skip_token ();
3625
3626 std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
3627 if (bound == nullptr)
3628 {
3629 /* not an error: bound is allowed to be null as trailing plus is
3630 * allowed */
3631 return type_param_bounds;
3632 }
3633
3634 type_param_bounds.push_back (std::move (bound));
3635 }
3636
3637 type_param_bounds.shrink_to_fit ();
3638 return type_param_bounds;
3639}
3640
3641/* Parses type parameter bounds in where clause or generic arguments, with end
3642 * token handling. */
3643template <typename ManagedTokenSource>
3644template <typename EndTokenPred>
3645std::vector<std::unique_ptr<AST::TypeParamBound>>
3646Parser<ManagedTokenSource>::parse_type_param_bounds (EndTokenPred is_end_token)
3647{
3648 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
3649
3650 std::unique_ptr<AST::TypeParamBound> initial_bound
3651 = parse_type_param_bound ();
3652
3653 // quick exit if null
3654 if (initial_bound == nullptr)
3655 {
3656 /* error? type param bounds must have at least one term, but are bounds
3657 * optional? */
3658 return type_param_bounds;
3659 }
3660 type_param_bounds.push_back (std::move (initial_bound));
3661
3662 while (lexer.peek_token ()->get_id () == PLUS)
3663 {
3664 lexer.skip_token ();
3665
3666 // break if end token character
3667 if (is_end_token (lexer.peek_token ()->get_id ()))
3668 break;
3669
3670 std::unique_ptr<AST::TypeParamBound> bound = parse_type_param_bound ();
3671 if (bound == nullptr)
3672 {
3673 // TODO how wise is it to ditch all bounds if only one failed?
3674 Error error (lexer.peek_token ()->get_locus (),
3675 "failed to parse type param bound in type param bounds");
3676 add_error (std::move (error));
3677
3678 return {};
3679 }
3680
3681 type_param_bounds.push_back (std::move (bound));
3682 }
3683
3684 type_param_bounds.shrink_to_fit ();
3685 return type_param_bounds;
3686}
3687
3688/* Parses a single type parameter bound in a where clause or generic argument.
3689 * Does not parse the '+' between arguments. */
3690template <typename ManagedTokenSource>
3691std::unique_ptr<AST::TypeParamBound>
3692Parser<ManagedTokenSource>::parse_type_param_bound ()
3693{
3694 // shitty cheat way of determining lifetime or trait bound - test for
3695 // lifetime
3696 const_TokenPtr t = lexer.peek_token ();
3697 switch (t->get_id ())
3698 {
3699 case LIFETIME:
3700 return std::unique_ptr<AST::Lifetime> (
3701 new AST::Lifetime (parse_lifetime ()));
3702 case LEFT_PAREN:
3703 case QUESTION_MARK:
3704 case FOR:
3705 case IDENTIFIER:
3706 case SUPER:
3707 case SELF:
3708 case SELF_ALIAS:
3709 case CRATE:
3710 case DOLLAR_SIGN:
3711 return parse_trait_bound ();
3712 default:
3713 // don't error - assume this is fine TODO
3714 return nullptr;
3715 }
3716}
3717
3718// Parses a trait bound type param bound.
3719template <typename ManagedTokenSource>
3720std::unique_ptr<AST::TraitBound>
3721Parser<ManagedTokenSource>::parse_trait_bound ()
3722{
3723 bool has_parens = false;
3724 bool has_question_mark = false;
3725
3726 Location locus = lexer.peek_token ()->get_locus ();
3727
3728 // handle trait bound being in parentheses
3729 if (lexer.peek_token ()->get_id () == LEFT_PAREN)
3730 {
3731 has_parens = true;
3732 lexer.skip_token ();
3733 }
3734
3735 // handle having question mark (optional)
3736 if (lexer.peek_token ()->get_id () == QUESTION_MARK)
3737 {
3738 has_question_mark = true;
3739 lexer.skip_token ();
3740 }
3741
3742 /* parse for lifetimes, if it exists (although empty for lifetimes is ok to
3743 * handle this) */
3744 std::vector<AST::LifetimeParam> for_lifetimes;
3745 if (lexer.peek_token ()->get_id () == FOR)
3746 for_lifetimes = parse_for_lifetimes ();
3747
3748 // handle TypePath
3749 AST::TypePath type_path = parse_type_path ();
3750
3751 // handle closing parentheses
3752 if (has_parens)
3753 {
3754 if (!skip_token (RIGHT_PAREN))
3755 {
3756 return nullptr;
3757 }
3758 }
3759
3760 return std::unique_ptr<AST::TraitBound> (
3761 new AST::TraitBound (std::move (type_path), locus, has_parens,
3762 has_question_mark, std::move (for_lifetimes)));
3763}
3764
3765// Parses lifetime bounds.
3766template <typename ManagedTokenSource>
3767std::vector<AST::Lifetime>
3768Parser<ManagedTokenSource>::parse_lifetime_bounds ()
3769{
3770 std::vector<AST::Lifetime> lifetime_bounds;
3771
3772 while (true)
3773 {
3774 AST::Lifetime lifetime = parse_lifetime ();
3775
3776 // quick exit for parsing failure
3777 if (lifetime.is_error ())
3778 break;
3779
3780 lifetime_bounds.push_back (std::move (lifetime));
3781
3782 /* plus is maybe not allowed at end - spec defines it weirdly, so
3783 * assuming allowed at end */
3784 if (lexer.peek_token ()->get_id () != PLUS)
3785 break;
3786
3787 lexer.skip_token ();
3788 }
3789
3790 lifetime_bounds.shrink_to_fit ();
3791 return lifetime_bounds;
3792}
3793
3794// Parses lifetime bounds, with added check for ending token.
3795template <typename ManagedTokenSource>
3796template <typename EndTokenPred>
3797std::vector<AST::Lifetime>
3798Parser<ManagedTokenSource>::parse_lifetime_bounds (EndTokenPred is_end_token)
3799{
3800 std::vector<AST::Lifetime> lifetime_bounds;
3801
3802 while (!is_end_token (lexer.peek_token ()->get_id ()))
3803 {
3804 AST::Lifetime lifetime = parse_lifetime ();
3805
3806 if (lifetime.is_error ())
3807 {
3808 /* TODO: is it worth throwing away all lifetime bound info just
3809 * because one failed? */
3810 Error error (lexer.peek_token ()->get_locus (),
3811 "failed to parse lifetime in lifetime bounds");
3812 add_error (std::move (error));
3813
3814 return {};
3815 }
3816
3817 lifetime_bounds.push_back (std::move (lifetime));
3818
3819 /* plus is maybe not allowed at end - spec defines it weirdly, so
3820 * assuming allowed at end */
3821 if (lexer.peek_token ()->get_id () != PLUS)
3822 break;
3823
3824 lexer.skip_token ();
3825 }
3826
3827 lifetime_bounds.shrink_to_fit ();
3828 return lifetime_bounds;
3829}
3830
3831/* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not
3832 * existing. */
3833template <typename ManagedTokenSource>
3834AST::Lifetime
3835Parser<ManagedTokenSource>::parse_lifetime ()
3836{
3837 const_TokenPtr lifetime_tok = lexer.peek_token ();
3838 Location locus = lifetime_tok->get_locus ();
3839 // create error lifetime if doesn't exist
3840 if (lifetime_tok->get_id () != LIFETIME)
3841 {
3842 return AST::Lifetime::error ();
3843 }
3844 lexer.skip_token ();
3845
3846 std::string lifetime_ident = lifetime_tok->get_str ();
3847
3848 if (lifetime_ident == "'static")
3849 {
3850 return AST::Lifetime (AST::Lifetime::STATIC, "", locus);
3851 }
3852 else if (lifetime_ident == "'_")
3853 {
3854 return AST::Lifetime (AST::Lifetime::WILDCARD, "", locus);
3855 }
3856 else
3857 {
3858 return AST::Lifetime (AST::Lifetime::NAMED, std::move (lifetime_ident),
3859 locus);
3860 }
3861}
3862
3863// Parses a "type alias" (typedef) item.
3864template <typename ManagedTokenSource>
3865std::unique_ptr<AST::TypeAlias>
3866Parser<ManagedTokenSource>::parse_type_alias (AST::Visibility vis,
3867 AST::AttrVec outer_attrs)
3868{
3869 Location locus = lexer.peek_token ()->get_locus ();
3870 skip_token (TYPE);
3871
3872 // TODO: use this token for identifier when finished that
3873 const_TokenPtr alias_name_tok = expect_token (IDENTIFIER);
3874 if (alias_name_tok == nullptr)
3875 {
3876 Error error (lexer.peek_token ()->get_locus (),
3877 "could not parse identifier in type alias");
3878 add_error (std::move (error));
3879
3880 skip_after_semicolon ();
3881 return nullptr;
3882 }
3883 Identifier alias_name = alias_name_tok->get_str ();
3884
3885 // parse generic params, which may not exist
3886 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3887 = parse_generic_params_in_angles ();
3888
3889 // parse where clause, which may not exist
3890 AST::WhereClause where_clause = parse_where_clause ();
3891
3892 if (!skip_token (EQUAL))
3893 {
3894 skip_after_semicolon ();
3895 return nullptr;
3896 }
3897
3898 std::unique_ptr<AST::Type> type_to_alias = parse_type ();
3899
3900 if (!skip_token (SEMICOLON))
3901 {
3902 // should be skipping past this, not the next line
3903 return nullptr;
3904 }
3905
3906 return std::unique_ptr<AST::TypeAlias> (
3907 new AST::TypeAlias (std::move (alias_name), std::move (generic_params),
3908 std::move (where_clause), std::move (type_to_alias),
3909 std::move (vis), std::move (outer_attrs), locus));
3910}
3911
3912// Parse a struct item AST node.
3913template <typename ManagedTokenSource>
3914std::unique_ptr<AST::Struct>
3915Parser<ManagedTokenSource>::parse_struct (AST::Visibility vis,
3916 AST::AttrVec outer_attrs)
3917{
3918 /* TODO: determine best way to parse the proper struct vs tuple struct -
3919 * share most of initial constructs so lookahead might be impossible, and if
3920 * not probably too expensive. Best way is probably unified parsing for the
3921 * initial parts and then pass them in as params to more derived functions.
3922 * Alternatively, just parse everything in this one function - do this if
3923 * function not too long. */
3924
3925 /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{'
3926 * struct_fields? '}' | ';' ) */
3927 /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')'
3928 * where_clause? ';' */
3929 Location locus = lexer.peek_token ()->get_locus ();
3930 skip_token (STRUCT_TOK);
3931
3932 // parse struct name
3933 const_TokenPtr name_tok = expect_token (IDENTIFIER);
3934 if (name_tok == nullptr)
3935 {
3936 Error error (lexer.peek_token ()->get_locus (),
3937 "could not parse struct or tuple struct identifier");
3938 add_error (std::move (error));
3939
3940 // skip after somewhere?
3941 return nullptr;
3942 }
3943 Identifier struct_name = name_tok->get_str ();
3944
3945 // parse generic params, which may or may not exist
3946 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
3947 = parse_generic_params_in_angles ();
3948
3949 // branch on next token - determines whether proper struct or tuple struct
3950 if (lexer.peek_token ()->get_id () == LEFT_PAREN)
3951 {
3952 // tuple struct
3953
3954 // skip left parenthesis
3955 lexer.skip_token ();
3956
3957 // parse tuple fields
3958 std::vector<AST::TupleField> tuple_fields;
3959 // Might be empty tuple for unit tuple struct.
3960 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
3961 tuple_fields = std::vector<AST::TupleField> ();
3962 else
3963 tuple_fields = parse_tuple_fields ();
3964
3965 // tuple parameters must have closing parenthesis
3966 if (!skip_token (RIGHT_PAREN))
3967 {
3968 skip_after_semicolon ();
3969 return nullptr;
3970 }
3971
3972 // parse where clause, which is optional
3973 AST::WhereClause where_clause = parse_where_clause ();
3974
3975 if (!skip_token (SEMICOLON))
3976 {
3977 // can't skip after semicolon because it's meant to be here
3978 return nullptr;
3979 }
3980
3981 return std::unique_ptr<AST::TupleStruct> (
3982 new AST::TupleStruct (std::move (tuple_fields), std::move (struct_name),
3983 std::move (generic_params),
3984 std::move (where_clause), std::move (vis),
3985 std::move (outer_attrs), locus));
3986 }
3987
3988 // assume it is a proper struct being parsed and continue outside of switch
3989 // - label only here to suppress warning
3990
3991 // parse where clause, which is optional
3992 AST::WhereClause where_clause = parse_where_clause ();
3993
3994 // branch on next token - determines whether struct is a unit struct
3995 const_TokenPtr t = lexer.peek_token ();
3996 switch (t->get_id ())
3997 {
3998 case LEFT_CURLY: {
3999 // struct with body
4000
4001 // skip curly bracket
4002 lexer.skip_token ();
4003
4004 // parse struct fields, if any
4005 std::vector<AST::StructField> struct_fields
4006 = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
4007
4008 if (!skip_token (RIGHT_CURLY))
4009 {
4010 // skip somewhere?
4011 return nullptr;
4012 }
4013
4014 return std::unique_ptr<AST::StructStruct> (new AST::StructStruct (
4015 std::move (struct_fields), std::move (struct_name),
4016 std::move (generic_params), std::move (where_clause), false,
4017 std::move (vis), std::move (outer_attrs), locus));
4018 }
4019 case SEMICOLON:
4020 // unit struct declaration
4021
4022 lexer.skip_token ();
4023
4024 return std::unique_ptr<AST::StructStruct> (
4025 new AST::StructStruct (std::move (struct_name),
4026 std::move (generic_params),
4027 std::move (where_clause), std::move (vis),
4028 std::move (outer_attrs), locus));
4029 default:
4030 add_error (Error (t->get_locus (),
4031 "unexpected token %qs in struct declaration",
4032 t->get_token_description ()));
4033
4034 // skip somewhere?
4035 return nullptr;
4036 }
4037}
4038
4039// Parses struct fields in struct declarations.
4040template <typename ManagedTokenSource>
4041std::vector<AST::StructField>
4042Parser<ManagedTokenSource>::parse_struct_fields ()
4043{
4044 std::vector<AST::StructField> fields;
4045
4046 AST::StructField initial_field = parse_struct_field ();
4047
4048 // Return empty field list if no field there
4049 if (initial_field.is_error ())
4050 return fields;
4051
4052 fields.push_back (std::move (initial_field));
4053
4054 while (lexer.peek_token ()->get_id () == COMMA)
4055 {
4056 lexer.skip_token ();
4057
4058 AST::StructField field = parse_struct_field ();
4059
4060 if (field.is_error ())
4061 {
4062 // would occur with trailing comma, so allowed
4063 break;
4064 }
4065
4066 fields.push_back (std::move (field));
4067 }
4068
4069 fields.shrink_to_fit ();
4070 return fields;
4071 // TODO: template if possible (parse_non_ptr_seq)
4072}
4073
4074// Parses struct fields in struct declarations.
4075template <typename ManagedTokenSource>
4076template <typename EndTokenPred>
4077std::vector<AST::StructField>
4078Parser<ManagedTokenSource>::parse_struct_fields (EndTokenPred is_end_tok)
4079{
4080 std::vector<AST::StructField> fields;
4081
4082 AST::StructField initial_field = parse_struct_field ();
4083
4084 // Return empty field list if no field there
4085 if (initial_field.is_error ())
4086 return fields;
4087
4088 fields.push_back (std::move (initial_field));
4089
4090 while (lexer.peek_token ()->get_id () == COMMA)
4091 {
4092 lexer.skip_token ();
4093
4094 if (is_end_tok (lexer.peek_token ()->get_id ()))
4095 break;
4096
4097 AST::StructField field = parse_struct_field ();
4098 if (field.is_error ())
4099 {
4100 /* TODO: should every field be ditched just because one couldn't be
4101 * parsed? */
4102 Error error (lexer.peek_token ()->get_locus (),
4103 "failed to parse struct field in struct fields");
4104 add_error (std::move (error));
4105
4106 return {};
4107 }
4108
4109 fields.push_back (std::move (field));
4110 }
4111
4112 fields.shrink_to_fit ();
4113 return fields;
4114 // TODO: template if possible (parse_non_ptr_seq)
4115}
4116
4117// Parses a single struct field (in a struct definition). Does not parse
4118// commas.
4119template <typename ManagedTokenSource>
4120AST::StructField
4121Parser<ManagedTokenSource>::parse_struct_field ()
4122{
4123 // parse outer attributes, if they exist
4124 AST::AttrVec outer_attrs = parse_outer_attributes ();
4125
4126 // parse visibility, if it exists
4127 AST::Visibility vis = parse_visibility ();
4128
4129 Location locus = lexer.peek_token ()->get_locus ();
4130
4131 // parse field name
4132 const_TokenPtr field_name_tok = lexer.peek_token ();
4133 if (field_name_tok->get_id () != IDENTIFIER)
4134 {
4135 // if not identifier, assumes there is no struct field and exits - not
4136 // necessarily error
4137 return AST::StructField::create_error ();
4138 }
4139 Identifier field_name = field_name_tok->get_str ();
4140 lexer.skip_token ();
4141
4142 if (!skip_token (COLON))
4143 {
4144 // skip after somewhere?
4145 return AST::StructField::create_error ();
4146 }
4147
4148 // parse field type - this is required
4149 std::unique_ptr<AST::Type> field_type = parse_type ();
4150 if (field_type == nullptr)
4151 {
4152 Error error (lexer.peek_token ()->get_locus (),
4153 "could not parse type in struct field definition");
4154 add_error (std::move (error));
4155
4156 // skip after somewhere
4157 return AST::StructField::create_error ();
4158 }
4159
4160 return AST::StructField (std::move (field_name), std::move (field_type),
4161 std::move (vis), locus, std::move (outer_attrs));
4162}
4163
4164// Parses tuple fields in tuple/tuple struct declarations.
4165template <typename ManagedTokenSource>
4166std::vector<AST::TupleField>
4167Parser<ManagedTokenSource>::parse_tuple_fields ()
4168{
4169 std::vector<AST::TupleField> fields;
4170
4171 AST::TupleField initial_field = parse_tuple_field ();
4172
4173 // Return empty field list if no field there
4174 if (initial_field.is_error ())
4175 {
4176 return fields;
4177 }
4178
4179 fields.push_back (std::move (initial_field));
4180
4181 // maybe think of a better control structure here - do-while with an initial
4182 // error state? basically, loop through field list until can't find any more
4183 // params HACK: all current syntax uses of tuple fields have them ending
4184 // with a right paren token
4185 const_TokenPtr t = lexer.peek_token ();
4186 while (t->get_id () == COMMA)
4187 {
4188 // skip comma if applies - e.g. trailing comma
4189 lexer.skip_token ();
4190
4191 // break out due to right paren if it exists
4192 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
4193 {
4194 break;
4195 }
4196
4197 AST::TupleField field = parse_tuple_field ();
4198 if (field.is_error ())
4199 {
4200 Error error (lexer.peek_token ()->get_locus (),
4201 "failed to parse tuple field in tuple fields");
4202 add_error (std::move (error));
4203
4204 return std::vector<AST::TupleField> ();
4205 }
4206
4207 fields.push_back (std::move (field));
4208
4209 t = lexer.peek_token ();
4210 }
4211
4212 fields.shrink_to_fit ();
4213 return fields;
4214
4215 // TODO: this shares basically all code with function params and struct
4216 // fields
4217 // - templates?
4218}
4219
4220/* Parses a single tuple struct field in a tuple struct definition. Does not
4221 * parse commas. */
4222template <typename ManagedTokenSource>
4223AST::TupleField
4224Parser<ManagedTokenSource>::parse_tuple_field ()
4225{
4226 // parse outer attributes if they exist
4227 AST::AttrVec outer_attrs = parse_outer_attributes ();
4228
4229 // parse visibility if it exists
4230 AST::Visibility vis = parse_visibility ();
4231
4232 Location locus = lexer.peek_token ()->get_locus ();
4233
4234 // parse type, which is required
4235 std::unique_ptr<AST::Type> field_type = parse_type ();
4236 if (field_type == nullptr)
4237 {
4238 // error if null
4239 Error error (lexer.peek_token ()->get_locus (),
4240 "could not parse type in tuple struct field");
4241 add_error (std::move (error));
4242
4243 // skip after something
4244 return AST::TupleField::create_error ();
4245 }
4246
4247 return AST::TupleField (std::move (field_type), std::move (vis), locus,
4248 std::move (outer_attrs));
4249}
4250
4251// Parses a Rust "enum" tagged union item definition.
4252template <typename ManagedTokenSource>
4253std::unique_ptr<AST::Enum>
4254Parser<ManagedTokenSource>::parse_enum (AST::Visibility vis,
4255 AST::AttrVec outer_attrs)
4256{
4257 Location locus = lexer.peek_token ()->get_locus ();
4258 skip_token (ENUM_TOK);
4259
4260 // parse enum name
4261 const_TokenPtr enum_name_tok = expect_token (IDENTIFIER);
4262 if (enum_name_tok == nullptr)
4263 return nullptr;
4264
4265 Identifier enum_name = enum_name_tok->get_str ();
4266
4267 // parse generic params (of enum container, not enum variants) if they exist
4268 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4269 = parse_generic_params_in_angles ();
4270
4271 // parse where clause if it exists
4272 AST::WhereClause where_clause = parse_where_clause ();
4273
4274 if (!skip_token (LEFT_CURLY))
4275 {
4276 skip_after_end_block ();
4277 return nullptr;
4278 }
4279
4280 // parse actual enum variant definitions
4281 std::vector<std::unique_ptr<AST::EnumItem>> enum_items
4282 = parse_enum_items ([] (TokenId id) { return id == RIGHT_CURLY; });
4283
4284 if (!skip_token (RIGHT_CURLY))
4285 {
4286 skip_after_end_block ();
4287 return nullptr;
4288 }
4289
4290 return std::unique_ptr<AST::Enum> (
4291 new AST::Enum (std::move (enum_name), std::move (vis),
4292 std::move (generic_params), std::move (where_clause),
4293 std::move (enum_items), std::move (outer_attrs), locus));
4294}
4295
4296// Parses the enum variants inside an enum definiton.
4297template <typename ManagedTokenSource>
4298std::vector<std::unique_ptr<AST::EnumItem>>
4299Parser<ManagedTokenSource>::parse_enum_items ()
4300{
4301 std::vector<std::unique_ptr<AST::EnumItem>> items;
4302
4303 std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
4304
4305 // Return empty item list if no field there
4306 if (initial_item == nullptr)
4307 return items;
4308
4309 items.push_back (std::move (initial_item));
4310
4311 while (lexer.peek_token ()->get_id () == COMMA)
4312 {
4313 lexer.skip_token ();
4314
4315 std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
4316 if (item == nullptr)
4317 {
4318 // this would occur with a trailing comma, which is allowed
4319 break;
4320 }
4321
4322 items.push_back (std::move (item));
4323 }
4324
4325 items.shrink_to_fit ();
4326 return items;
4327
4328 /* TODO: use template if doable (parse_non_ptr_sequence) */
4329}
4330
4331// Parses the enum variants inside an enum definiton.
4332template <typename ManagedTokenSource>
4333template <typename EndTokenPred>
4334std::vector<std::unique_ptr<AST::EnumItem>>
4335Parser<ManagedTokenSource>::parse_enum_items (EndTokenPred is_end_tok)
4336{
4337 std::vector<std::unique_ptr<AST::EnumItem>> items;
4338
4339 std::unique_ptr<AST::EnumItem> initial_item = parse_enum_item ();
4340
4341 // Return empty item list if no field there
4342 if (initial_item == nullptr)
4343 return items;
4344
4345 items.push_back (std::move (initial_item));
4346
4347 while (lexer.peek_token ()->get_id () == COMMA)
4348 {
4349 lexer.skip_token ();
4350
4351 if (is_end_tok (lexer.peek_token ()->get_id ()))
4352 break;
4353
4354 std::unique_ptr<AST::EnumItem> item = parse_enum_item ();
4355 if (item == nullptr)
4356 {
4357 /* TODO should this ignore all successfully parsed enum items just
4358 * because one failed? */
4359 Error error (lexer.peek_token ()->get_locus (),
4360 "failed to parse enum item in enum items");
4361 add_error (std::move (error));
4362
4363 return {};
4364 }
4365
4366 items.push_back (std::move (item));
4367 }
4368
4369 items.shrink_to_fit ();
4370 return items;
4371
4372 /* TODO: use template if doable (parse_non_ptr_sequence) */
4373}
4374
4375/* Parses a single enum variant item in an enum definition. Does not parse
4376 * commas. */
4377template <typename ManagedTokenSource>
4378std::unique_ptr<AST::EnumItem>
4379Parser<ManagedTokenSource>::parse_enum_item ()
4380{
4381 // parse outer attributes if they exist
4382 AST::AttrVec outer_attrs = parse_outer_attributes ();
4383
4384 // parse visibility, which may or may not exist
4385 AST::Visibility vis = parse_visibility ();
4386
4387 // parse name for enum item, which is required
4388 const_TokenPtr item_name_tok = lexer.peek_token ();
4389 if (item_name_tok->get_id () != IDENTIFIER)
4390 {
4391 // this may not be an error but it means there is no enum item here
4392 return nullptr;
4393 }
4394 lexer.skip_token ();
4395 Identifier item_name = item_name_tok->get_str ();
4396
4397 // branch based on next token
4398 const_TokenPtr t = lexer.peek_token ();
4399 switch (t->get_id ())
4400 {
4401 case LEFT_PAREN: {
4402 // tuple enum item
4403 lexer.skip_token ();
4404
4405 std::vector<AST::TupleField> tuple_fields;
4406 // Might be empty tuple for unit tuple enum variant.
4407 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
4408 tuple_fields = std::vector<AST::TupleField> ();
4409 else
4410 tuple_fields = parse_tuple_fields ();
4411
4412 if (!skip_token (RIGHT_PAREN))
4413 {
4414 // skip after somewhere
4415 return nullptr;
4416 }
4417
4418 return std::unique_ptr<AST::EnumItemTuple> (new AST::EnumItemTuple (
4419 std::move (item_name), std::move (vis), std::move (tuple_fields),
4420 std::move (outer_attrs), item_name_tok->get_locus ()));
4421 }
4422 case LEFT_CURLY: {
4423 // struct enum item
4424 lexer.skip_token ();
4425
4426 std::vector<AST::StructField> struct_fields
4427 = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
4428
4429 if (!skip_token (RIGHT_CURLY))
4430 {
4431 // skip after somewhere
4432 return nullptr;
4433 }
4434
4435 return std::unique_ptr<AST::EnumItemStruct> (new AST::EnumItemStruct (
4436 std::move (item_name), std::move (vis), std::move (struct_fields),
4437 std::move (outer_attrs), item_name_tok->get_locus ()));
4438 }
4439 case EQUAL: {
4440 // discriminant enum item
4441 lexer.skip_token ();
4442
4443 std::unique_ptr<AST::Expr> discriminant_expr = parse_expr ();
4444
4445 return std::unique_ptr<AST::EnumItemDiscriminant> (
4446 new AST::EnumItemDiscriminant (std::move (item_name), std::move (vis),
4447 std::move (discriminant_expr),
4448 std::move (outer_attrs),
4449 item_name_tok->get_locus ()));
4450 }
4451 default:
4452 // regular enum with just an identifier
4453 return std::unique_ptr<AST::EnumItem> (
4454 new AST::EnumItem (std::move (item_name), std::move (vis),
4455 std::move (outer_attrs),
4456 item_name_tok->get_locus ()));
4457 }
4458}
4459
4460// Parses a C-style (and C-compat) untagged union declaration.
4461template <typename ManagedTokenSource>
4462std::unique_ptr<AST::Union>
4463Parser<ManagedTokenSource>::parse_union (AST::Visibility vis,
4464 AST::AttrVec outer_attrs)
4465{
4466 /* hack - "weak keyword" by finding identifier called "union" (lookahead in
4467 * item switch) */
4468 const_TokenPtr union_keyword = expect_token (IDENTIFIER);
4469 rust_assert (union_keyword->get_str () == "union");
4470 Location locus = union_keyword->get_locus ();
4471
4472 // parse actual union name
4473 const_TokenPtr union_name_tok = expect_token (IDENTIFIER);
4474 if (union_name_tok == nullptr)
4475 {
4476 skip_after_next_block ();
4477 return nullptr;
4478 }
4479 Identifier union_name = union_name_tok->get_str ();
4480
4481 // parse optional generic parameters
4482 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4483 = parse_generic_params_in_angles ();
4484
4485 // parse optional where clause
4486 AST::WhereClause where_clause = parse_where_clause ();
4487
4488 if (!skip_token (LEFT_CURLY))
4489 {
4490 skip_after_end_block ();
4491 return nullptr;
4492 }
4493
4494 /* parse union inner items as "struct fields" because hey, syntax reuse.
4495 * Spec said so. */
4496 std::vector<AST::StructField> union_fields
4497 = parse_struct_fields ([] (TokenId id) { return id == RIGHT_CURLY; });
4498
4499 if (!skip_token (RIGHT_CURLY))
4500 {
4501 // skip after somewhere
4502 return nullptr;
4503 }
4504
4505 return std::unique_ptr<AST::Union> (
4506 new AST::Union (std::move (union_name), std::move (vis),
4507 std::move (generic_params), std::move (where_clause),
4508 std::move (union_fields), std::move (outer_attrs), locus));
4509}
4510
4511/* Parses a "constant item" (compile-time constant to maybe "inline"
4512 * throughout the program - like constexpr). */
4513template <typename ManagedTokenSource>
4514std::unique_ptr<AST::ConstantItem>
4515Parser<ManagedTokenSource>::parse_const_item (AST::Visibility vis,
4516 AST::AttrVec outer_attrs)
4517{
4518 Location locus = lexer.peek_token ()->get_locus ();
4519 skip_token (CONST);
4520
4521 /* get constant identifier - this is either a proper identifier or the _
4522 * wildcard */
4523 const_TokenPtr ident_tok = lexer.peek_token ();
4524 // make default identifier the underscore wildcard one
4525 std::string ident ("_");
4526 switch (ident_tok->get_id ())
4527 {
4528 case IDENTIFIER:
4529 ident = ident_tok->get_str ();
4530 lexer.skip_token ();
4531 break;
4532 case UNDERSCORE:
4533 // do nothing - identifier is already "_"
4534 lexer.skip_token ();
4535 break;
4536 default:
4537 add_error (
4538 Error (ident_tok->get_locus (),
4539 "expected item name (identifier or %<_%>) in constant item "
4540 "declaration - found %qs",
4541 ident_tok->get_token_description ()));
4542
4543 skip_after_semicolon ();
4544 return nullptr;
4545 }
4546
4547 if (!skip_token (COLON))
4548 {
4549 skip_after_semicolon ();
4550 return nullptr;
4551 }
4552
4553 // parse constant type (required)
4554 std::unique_ptr<AST::Type> type = parse_type ();
4555
4556 if (!skip_token (EQUAL))
4557 {
4558 skip_after_semicolon ();
4559 return nullptr;
4560 }
4561
4562 // parse constant expression (required)
4563 std::unique_ptr<AST::Expr> expr = parse_expr ();
4564
4565 if (!skip_token (SEMICOLON))
4566 {
4567 // skip somewhere?
4568 return nullptr;
4569 }
4570
4571 return std::unique_ptr<AST::ConstantItem> (
4572 new AST::ConstantItem (std::move (ident), std::move (vis), std::move (type),
4573 std::move (expr), std::move (outer_attrs), locus));
4574}
4575
4576// Parses a "static item" (static storage item, with 'static lifetime).
4577template <typename ManagedTokenSource>
4578std::unique_ptr<AST::StaticItem>
4579Parser<ManagedTokenSource>::parse_static_item (AST::Visibility vis,
4580 AST::AttrVec outer_attrs)
4581{
4582 Location locus = lexer.peek_token ()->get_locus ();
4583 skip_token (STATIC_TOK);
4584
4585 // determine whether static item is mutable
4586 bool is_mut = false;
4587 if (lexer.peek_token ()->get_id () == MUT)
4588 {
4589 is_mut = true;
4590 lexer.skip_token ();
4591 }
4592
4593 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4594 if (ident_tok == nullptr)
4595 return nullptr;
4596
4597 Identifier ident = ident_tok->get_str ();
4598
4599 if (!skip_token (COLON))
4600 {
4601 skip_after_semicolon ();
4602 return nullptr;
4603 }
4604
4605 // parse static item type (required)
4606 std::unique_ptr<AST::Type> type = parse_type ();
4607
4608 if (!skip_token (EQUAL))
4609 {
4610 skip_after_semicolon ();
4611 return nullptr;
4612 }
4613
4614 // parse static item expression (required)
4615 std::unique_ptr<AST::Expr> expr = parse_expr ();
4616
4617 if (!skip_token (SEMICOLON))
4618 {
4619 // skip after somewhere
4620 return nullptr;
4621 }
4622
4623 return std::unique_ptr<AST::StaticItem> (
4624 new AST::StaticItem (std::move (ident), is_mut, std::move (type),
4625 std::move (expr), std::move (vis),
4626 std::move (outer_attrs), locus));
4627}
4628
4629// Parses a trait definition item, including unsafe ones.
4630template <typename ManagedTokenSource>
4631std::unique_ptr<AST::Trait>
4632Parser<ManagedTokenSource>::parse_trait (AST::Visibility vis,
4633 AST::AttrVec outer_attrs)
4634{
4635 Location locus = lexer.peek_token ()->get_locus ();
4636 bool is_unsafe = false;
4637 if (lexer.peek_token ()->get_id () == UNSAFE)
4638 {
4639 is_unsafe = true;
4640 lexer.skip_token ();
4641 }
4642
4643 skip_token (TRAIT);
4644
4645 // parse trait name
4646 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4647 if (ident_tok == nullptr)
4648 return nullptr;
4649
4650 Identifier ident = ident_tok->get_str ();
4651
4652 // parse generic parameters (if they exist)
4653 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4654 = parse_generic_params_in_angles ();
4655
4656 // create placeholder type param bounds in case they don't exist
4657 std::vector<std::unique_ptr<AST::TypeParamBound>> type_param_bounds;
4658
4659 // parse type param bounds (if they exist)
4660 if (lexer.peek_token ()->get_id () == COLON)
4661 {
4662 lexer.skip_token ();
4663
4664 type_param_bounds = parse_type_param_bounds (
4665 [] (TokenId id) { return id == WHERE || id == LEFT_CURLY; });
4666 // type_param_bounds = parse_type_param_bounds ();
4667 }
4668
4669 // parse where clause (if it exists)
4670 AST::WhereClause where_clause = parse_where_clause ();
4671
4672 if (!skip_token (LEFT_CURLY))
4673 {
4674 skip_after_end_block ();
4675 return nullptr;
4676 }
4677
4678 // parse inner attrs (if they exist)
4679 AST::AttrVec inner_attrs = parse_inner_attributes ();
4680
4681 // parse trait items
4682 std::vector<std::unique_ptr<AST::TraitItem>> trait_items;
4683
4684 const_TokenPtr t = lexer.peek_token ();
4685 while (t->get_id () != RIGHT_CURLY)
4686 {
4687 std::unique_ptr<AST::TraitItem> trait_item = parse_trait_item ();
4688
4689 if (trait_item == nullptr)
4690 {
4691 Error error (lexer.peek_token ()->get_locus (),
4692 "failed to parse trait item in trait");
4693 add_error (std::move (error));
4694
4695 return nullptr;
4696 }
4697 trait_items.push_back (std::move (trait_item));
4698
4699 t = lexer.peek_token ();
4700 }
4701
4702 if (!skip_token (RIGHT_CURLY))
4703 {
4704 // skip after something
4705 return nullptr;
4706 }
4707
4708 trait_items.shrink_to_fit ();
4709 return std::unique_ptr<AST::Trait> (
4710 new AST::Trait (std::move (ident), is_unsafe, std::move (generic_params),
4711 std::move (type_param_bounds), std::move (where_clause),
4712 std::move (trait_items), std::move (vis),
4713 std::move (outer_attrs), std::move (inner_attrs), locus));
4714}
4715
4716// Parses a trait item used inside traits (not trait, the Item).
4717template <typename ManagedTokenSource>
4718std::unique_ptr<AST::TraitItem>
4719Parser<ManagedTokenSource>::parse_trait_item ()
4720{
4721 // parse outer attributes (if they exist)
4722 AST::AttrVec outer_attrs = parse_outer_attributes ();
4723
4724 // lookahead to determine what type of trait item to parse
4725 const_TokenPtr tok = lexer.peek_token ();
4726 switch (tok->get_id ())
4727 {
4728 case TYPE:
4729 return parse_trait_type (std::move (outer_attrs));
4730 case CONST:
4731 // disambiguate with function qualifier
4732 if (lexer.peek_token (1)->get_id () == IDENTIFIER)
4733 {
4734 return parse_trait_const (std::move (outer_attrs));
4735 }
4736 // else, fallthrough to function
4737 // TODO: find out how to disable gcc "implicit fallthrough" error
4738 gcc_fallthrough ();
4739 case UNSAFE:
4740 case EXTERN_TOK:
4741 case FN_TOK: {
4742 /* function and method can't be disambiguated by lookahead alone
4743 * (without a lot of work and waste), so either make a
4744 * "parse_trait_function_or_method" or parse here mostly and pass in
4745 * most parameters (or if short enough, parse whole thing here). */
4746 // parse function and method here
4747
4748 // parse function or method qualifiers
4749 AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
4750
4751 skip_token (FN_TOK);
4752
4753 // parse function or method name
4754 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4755 if (ident_tok == nullptr)
4756 return nullptr;
4757
4758 Identifier ident = ident_tok->get_str ();
4759
4760 // parse generic params
4761 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4762 = parse_generic_params_in_angles ();
4763
4764 if (!skip_token (LEFT_PAREN))
4765 {
4766 // skip after somewhere?
4767 return nullptr;
4768 }
4769
4770 /* now for function vs method disambiguation - method has opening
4771 * "self" param */
4772 AST::SelfParam self_param = parse_self_param ();
4773 /* FIXME: ensure that self param doesn't accidently consume tokens for
4774 * a function */
4775 bool is_method = false;
4776 if (!self_param.is_error ())
4777 {
4778 is_method = true;
4779
4780 /* skip comma so function and method regular params can be parsed
4781 * in same way */
4782 if (lexer.peek_token ()->get_id () == COMMA)
4783 lexer.skip_token ();
4784 }
4785
4786 // parse trait function params
4787 std::vector<AST::FunctionParam> function_params
4788 = parse_function_params (
4789 [] (TokenId id) { return id == RIGHT_PAREN; });
4790
4791 if (!skip_token (RIGHT_PAREN))
4792 {
4793 // skip after somewhere?
4794 return nullptr;
4795 }
4796
4797 // parse return type (optional)
4798 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
4799
4800 // parse where clause (optional)
4801 AST::WhereClause where_clause = parse_where_clause ();
4802
4803 // parse semicolon or function definition (in block)
4804 const_TokenPtr t = lexer.peek_token ();
4805 std::unique_ptr<AST::BlockExpr> definition = nullptr;
4806 switch (t->get_id ())
4807 {
4808 case SEMICOLON:
4809 lexer.skip_token ();
4810 // definition is already nullptr, so don't need to change it
4811 break;
4812 case LEFT_CURLY:
4813 definition = parse_block_expr ();
4814 /* FIXME: are these outer attributes meant to be passed into the
4815 * block? */
4816 break;
4817 default:
4818 add_error (
4819 Error (t->get_locus (),
4820 "expected %<;%> or definiton at the end of trait %s "
4821 "definition - found %qs instead",
4822 is_method ? "method" : "function",
4823 t->get_token_description ()));
4824
4825 // skip?
4826 return nullptr;
4827 }
4828
4829 // do actual if instead of ternary for return value optimisation
4830 if (is_method)
4831 {
4832 AST::TraitMethodDecl method_decl (std::move (ident),
4833 std::move (qualifiers),
4834 std::move (generic_params),
4835 std::move (self_param),
4836 std::move (function_params),
4837 std::move (return_type),
4838 std::move (where_clause));
4839
4840 // TODO: does this (method_decl) need move?
4841 return std::unique_ptr<AST::TraitItemMethod> (
4842 new AST::TraitItemMethod (std::move (method_decl),
4843 std::move (definition),
4844 std::move (outer_attrs),
4845 tok->get_locus ()));
4846 }
4847 else
4848 {
4849 AST::TraitFunctionDecl function_decl (std::move (ident),
4850 std::move (qualifiers),
4851 std::move (generic_params),
4852 std::move (function_params),
4853 std::move (return_type),
4854 std::move (where_clause));
4855
4856 return std::unique_ptr<AST::TraitItemFunc> (new AST::TraitItemFunc (
4857 std::move (function_decl), std::move (definition),
4858 std::move (outer_attrs), tok->get_locus ()));
4859 }
4860 }
4861 default: {
4862 // TODO: try and parse macro invocation semi - if fails, maybe error.
4863 std::unique_ptr<AST::TraitItem> macro_invoc
4864 = parse_macro_invocation_semi (outer_attrs);
4865
4866 if (macro_invoc == nullptr)
4867 {
4868 // TODO: error?
4869 return nullptr;
4870 }
4871 else
4872 {
4873 return macro_invoc;
4874 }
4875 /* FIXME: macro invocations can only start with certain tokens. be
4876 * more picky with these? */
4877 }
4878 }
4879}
4880
4881// Parse a typedef trait item.
4882template <typename ManagedTokenSource>
4883std::unique_ptr<AST::TraitItemType>
4884Parser<ManagedTokenSource>::parse_trait_type (AST::AttrVec outer_attrs)
4885{
4886 Location locus = lexer.peek_token ()->get_locus ();
4887 skip_token (TYPE);
4888
4889 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4890 if (ident_tok == nullptr)
4891 return nullptr;
4892
4893 Identifier ident = ident_tok->get_str ();
4894
4895 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
4896
4897 // parse optional colon
4898 if (lexer.peek_token ()->get_id () == COLON)
4899 {
4900 lexer.skip_token ();
4901
4902 // parse optional type param bounds
4903 bounds
4904 = parse_type_param_bounds ([] (TokenId id) { return id == SEMICOLON; });
4905 // bounds = parse_type_param_bounds ();
4906 }
4907
4908 if (!skip_token (SEMICOLON))
4909 {
4910 // skip?
4911 return nullptr;
4912 }
4913
4914 return std::unique_ptr<AST::TraitItemType> (
4915 new AST::TraitItemType (std::move (ident), std::move (bounds),
4916 std::move (outer_attrs), locus));
4917}
4918
4919// Parses a constant trait item.
4920template <typename ManagedTokenSource>
4921std::unique_ptr<AST::TraitItemConst>
4922Parser<ManagedTokenSource>::parse_trait_const (AST::AttrVec outer_attrs)
4923{
4924 Location locus = lexer.peek_token ()->get_locus ();
4925 skip_token (CONST);
4926
4927 // parse constant item name
4928 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
4929 if (ident_tok == nullptr)
4930 return nullptr;
4931
4932 Identifier ident = ident_tok->get_str ();
4933
4934 if (!skip_token (COLON))
4935 {
4936 skip_after_semicolon ();
4937 return nullptr;
4938 }
4939
4940 // parse constant trait item type
4941 std::unique_ptr<AST::Type> type = parse_type ();
4942
4943 // parse constant trait body expression, if it exists
4944 std::unique_ptr<AST::Expr> const_body = nullptr;
4945 if (lexer.peek_token ()->get_id () == EQUAL)
4946 {
4947 lexer.skip_token ();
4948
4949 // expression must exist, so parse it
4950 const_body = parse_expr ();
4951 }
4952
4953 if (!skip_token (SEMICOLON))
4954 {
4955 // skip after something?
4956 return nullptr;
4957 }
4958
4959 return std::unique_ptr<AST::TraitItemConst> (
4960 new AST::TraitItemConst (std::move (ident), std::move (type),
4961 std::move (const_body), std::move (outer_attrs),
4962 locus));
4963}
4964
4965/* Parses a struct "impl" item (both inherent impl and trait impl can be
4966 * parsed here), */
4967template <typename ManagedTokenSource>
4968std::unique_ptr<AST::Impl>
4969Parser<ManagedTokenSource>::parse_impl (AST::Visibility vis,
4970 AST::AttrVec outer_attrs)
4971{
4972 /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
4973 * must be a trait impl. However, this isn't enough for full disambiguation,
4974 * so don't branch here. */
4975 Location locus = lexer.peek_token ()->get_locus ();
4976 bool is_unsafe = false;
4977 if (lexer.peek_token ()->get_id () == UNSAFE)
4978 {
4979 lexer.skip_token ();
4980 is_unsafe = true;
4981 }
4982
4983 if (!skip_token (IMPL))
4984 {
4985 skip_after_next_block ();
4986 return nullptr;
4987 }
4988
4989 // parse generic params (shared by trait and inherent impls)
4990 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
4991 = parse_generic_params_in_angles ();
4992
4993 // Again, trait impl-only feature, but optional one, so can be used for
4994 // branching yet.
4995 bool has_exclam = false;
4996 if (lexer.peek_token ()->get_id () == EXCLAM)
4997 {
4998 lexer.skip_token ();
4999 has_exclam = true;
5000 }
5001
5002 /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
5003 * doesn't parse too much and not work. */
5004 AST::TypePath type_path = parse_type_path ();
5005 if (type_path.is_error () || lexer.peek_token ()->get_id () != FOR)
5006 {
5007 /* cannot parse type path (or not for token next, at least), so must be
5008 * inherent impl */
5009
5010 // hacky conversion of TypePath stack object to Type pointer
5011 std::unique_ptr<AST::Type> type = nullptr;
5012 if (!type_path.is_error ())
5013 type = std::unique_ptr<AST::TypePath> (
5014 new AST::TypePath (std::move (type_path)));
5015 else
5016 type = parse_type ();
5017
5018 // Type is required, so error if null
5019 if (type == nullptr)
5020 {
5021 Error error (lexer.peek_token ()->get_locus (),
5022 "could not parse type in inherent impl");
5023 add_error (std::move (error));
5024
5025 skip_after_next_block ();
5026 return nullptr;
5027 }
5028
5029 // parse optional where clause
5030 AST::WhereClause where_clause = parse_where_clause ();
5031
5032 if (!skip_token (LEFT_CURLY))
5033 {
5034 // TODO: does this still skip properly?
5035 skip_after_end_block ();
5036 return nullptr;
5037 }
5038
5039 // parse inner attributes (optional)
5040 AST::AttrVec inner_attrs = parse_inner_attributes ();
5041
5042 // parse inherent impl items
5043 std::vector<std::unique_ptr<AST::InherentImplItem>> impl_items;
5044
5045 const_TokenPtr t = lexer.peek_token ();
5046 while (t->get_id () != RIGHT_CURLY)
5047 {
5048 std::unique_ptr<AST::InherentImplItem> impl_item
5049 = parse_inherent_impl_item ();
5050
5051 if (impl_item == nullptr)
5052 {
5053 Error error (
5054 lexer.peek_token ()->get_locus (),
5055 "failed to parse inherent impl item in inherent impl");
5056 add_error (std::move (error));
5057
5058 return nullptr;
5059 }
5060
5061 impl_items.push_back (std::move (impl_item));
5062
5063 t = lexer.peek_token ();
5064 }
5065
5066 if (!skip_token (RIGHT_CURLY))
5067 {
5068 // skip somewhere
5069 return nullptr;
5070 }
5071
5072 // DEBUG
5073 rust_debug ("successfully parsed inherent impl");
5074
5075 impl_items.shrink_to_fit ();
5076
5077 return std::unique_ptr<AST::InherentImpl> (new AST::InherentImpl (
5078 std::move (impl_items), std::move (generic_params), std::move (type),
5079 std::move (where_clause), std::move (vis), std::move (inner_attrs),
5080 std::move (outer_attrs), locus));
5081 }
5082 else
5083 {
5084 // type path must both be valid and next token is for, so trait impl
5085 if (!skip_token (FOR))
5086 {
5087 skip_after_next_block ();
5088 return nullptr;
5089 }
5090
5091 // parse type
5092 std::unique_ptr<AST::Type> type = parse_type ();
5093 // ensure type is included as it is required
5094 if (type == nullptr)
5095 {
5096 Error error (lexer.peek_token ()->get_locus (),
5097 "could not parse type in trait impl");
5098 add_error (std::move (error));
5099
5100 skip_after_next_block ();
5101 return nullptr;
5102 }
5103
5104 // parse optional where clause
5105 AST::WhereClause where_clause = parse_where_clause ();
5106
5107 if (!skip_token (LEFT_CURLY))
5108 {
5109 // TODO: does this still skip properly?
5110 skip_after_end_block ();
5111 return nullptr;
5112 }
5113
5114 // parse inner attributes (optional)
5115 AST::AttrVec inner_attrs = parse_inner_attributes ();
5116
5117 // parse trait impl items
5118 std::vector<std::unique_ptr<AST::TraitImplItem>> impl_items;
5119
5120 const_TokenPtr t = lexer.peek_token ();
5121 while (t->get_id () != RIGHT_CURLY)
5122 {
5123 std::unique_ptr<AST::TraitImplItem> impl_item
5124 = parse_trait_impl_item ();
5125
5126 if (impl_item == nullptr)
5127 {
5128 Error error (lexer.peek_token ()->get_locus (),
5129 "failed to parse trait impl item in trait impl");
5130 add_error (std::move (error));
5131
5132 return nullptr;
5133 }
5134
5135 impl_items.push_back (std::move (impl_item));
5136
5137 t = lexer.peek_token ();
5138
5139 // DEBUG
5140 rust_debug ("successfully parsed a trait impl item");
5141 }
5142 // DEBUG
5143 rust_debug ("successfully finished trait impl items");
5144
5145 if (!skip_token (RIGHT_CURLY))
5146 {
5147 // skip somewhere
5148 return nullptr;
5149 }
5150
5151 // DEBUG
5152 rust_debug ("successfully parsed trait impl");
5153
5154 impl_items.shrink_to_fit ();
5155
5156 return std::unique_ptr<AST::TraitImpl> (
5157 new AST::TraitImpl (std::move (type_path), is_unsafe, has_exclam,
5158 std::move (impl_items), std::move (generic_params),
5159 std::move (type), std::move (where_clause),
5160 std::move (vis), std::move (inner_attrs),
5161 std::move (outer_attrs), locus));
5162 }
5163}
5164
5165// Parses a single inherent impl item (item inside an inherent impl block).
5166template <typename ManagedTokenSource>
5167std::unique_ptr<AST::InherentImplItem>
5168Parser<ManagedTokenSource>::parse_inherent_impl_item ()
5169{
5170 // parse outer attributes (if they exist)
5171 AST::AttrVec outer_attrs = parse_outer_attributes ();
5172
5173 // TODO: cleanup - currently an unreadable mess
5174
5175 // branch on next token:
5176 const_TokenPtr t = lexer.peek_token ();
5177 switch (t->get_id ())
5178 {
5179 case IDENTIFIER:
5180 // FIXME: Arthur: Do we need to some lookahead here?
5181 return parse_macro_invocation_semi (outer_attrs);
5182 case SUPER:
5183 case SELF:
5184 case CRATE:
5185 case PUB: {
5186 // visibility, so not a macro invocation semi - must be constant,
5187 // function, or method
5188 AST::Visibility vis = parse_visibility ();
5189
5190 // TODO: is a recursive call to parse_inherent_impl_item better?
5191 switch (lexer.peek_token ()->get_id ())
5192 {
5193 case EXTERN_TOK:
5194 case UNSAFE:
5195 case FN_TOK:
5196 // function or method
5197 return parse_inherent_impl_function_or_method (std::move (vis),
5198 std::move (
5199 outer_attrs));
5200 case CONST:
5201 // lookahead to resolve production - could be function/method or
5202 // const item
5203 t = lexer.peek_token (1);
5204
5205 switch (t->get_id ())
5206 {
5207 case IDENTIFIER:
5208 case UNDERSCORE:
5209 return parse_const_item (std::move (vis),
5210 std::move (outer_attrs));
5211 case UNSAFE:
5212 case EXTERN_TOK:
5213 case FN_TOK:
5214 return parse_inherent_impl_function_or_method (std::move (vis),
5215 std::move (
5216 outer_attrs));
5217 default:
5218 add_error (Error (t->get_locus (),
5219 "unexpected token %qs in some sort of const "
5220 "item in inherent impl",
5221 t->get_token_description ()));
5222
5223 lexer.skip_token (1); // TODO: is this right thing to do?
5224 return nullptr;
5225 }
5226 default:
5227 add_error (
5228 Error (t->get_locus (),
5229 "unrecognised token %qs for item in inherent impl",
5230 t->get_token_description ()));
5231 // skip?
5232 return nullptr;
5233 }
5234 }
5235 case EXTERN_TOK:
5236 case UNSAFE:
5237 case FN_TOK:
5238 // function or method
5239 return parse_inherent_impl_function_or_method (
5240 AST::Visibility::create_private (), std::move (outer_attrs));
5241 case CONST:
5242 /* lookahead to resolve production - could be function/method or const
5243 * item */
5244 t = lexer.peek_token (1);
5245
5246 switch (t->get_id ())
5247 {
5248 case IDENTIFIER:
5249 case UNDERSCORE:
5250 return parse_const_item (AST::Visibility::create_private (),
5251 std::move (outer_attrs));
5252 case UNSAFE:
5253 case EXTERN_TOK:
5254 case FN_TOK:
5255 return parse_inherent_impl_function_or_method (
5256 AST::Visibility::create_private (), std::move (outer_attrs));
5257 default:
5258 add_error (Error (t->get_locus (),
5259 "unexpected token %qs in some sort of const item "
5260 "in inherent impl",
5261 t->get_token_description ()));
5262
5263 lexer.skip_token (1); // TODO: is this right thing to do?
5264 return nullptr;
5265 }
5266 gcc_unreachable ();
5267 default:
5268 add_error (Error (t->get_locus (),
5269 "unrecognised token %qs for item in inherent impl",
5270 t->get_token_description ()));
5271
5272 // skip?
5273 return nullptr;
5274 }
5275}
5276
5277/* For internal use only by parse_inherent_impl_item() - splits giant method
5278 * into smaller ones and prevents duplication of logic. Strictly, this parses
5279 * a function or method item inside an inherent impl item block. */
5280// TODO: make this a templated function with "return type" as type param -
5281// InherentImplItem is this specialisation of the template while TraitImplItem
5282// will be the other.
5283template <typename ManagedTokenSource>
5284std::unique_ptr<AST::InherentImplItem>
5285Parser<ManagedTokenSource>::parse_inherent_impl_function_or_method (
5286 AST::Visibility vis, AST::AttrVec outer_attrs)
5287{
5288 Location locus = lexer.peek_token ()->get_locus ();
5289 // parse function or method qualifiers
5290 AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
5291
5292 skip_token (FN_TOK);
5293
5294 // parse function or method name
5295 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5296 if (ident_tok == nullptr)
5297 return nullptr;
5298
5299 Identifier ident = ident_tok->get_str ();
5300
5301 // parse generic params
5302 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5303 = parse_generic_params_in_angles ();
5304
5305 if (!skip_token (LEFT_PAREN))
5306 {
5307 // skip after somewhere?
5308 return nullptr;
5309 }
5310
5311 // now for function vs method disambiguation - method has opening "self"
5312 // param
5313 AST::SelfParam self_param = parse_self_param ();
5314 /* FIXME: ensure that self param doesn't accidently consume tokens for a
5315 * function one idea is to lookahead up to 4 tokens to see whether self is
5316 * one of them */
5317 bool is_method = false;
5318 if (!self_param.is_error ())
5319 {
5320 is_method = true;
5321
5322 /* skip comma so function and method regular params can be parsed in
5323 * same way */
5324 if (lexer.peek_token ()->get_id () == COMMA)
5325 lexer.skip_token ();
5326 }
5327
5328 // parse trait function params
5329 std::vector<AST::FunctionParam> function_params
5330 = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
5331
5332 if (!skip_token (RIGHT_PAREN))
5333 {
5334 skip_after_end_block ();
5335 return nullptr;
5336 }
5337
5338 // parse return type (optional)
5339 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
5340
5341 // parse where clause (optional)
5342 AST::WhereClause where_clause = parse_where_clause ();
5343
5344 // parse function definition (in block) - semicolon not allowed
5345 if (lexer.peek_token ()->get_id () == SEMICOLON)
5346 {
5347 Error error (lexer.peek_token ()->get_locus (),
5348 "%s declaration in inherent impl not allowed - must have "
5349 "a definition",
5350 is_method ? "method" : "function");
5351 add_error (std::move (error));
5352
5353 lexer.skip_token ();
5354 return nullptr;
5355 }
5356 std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
5357 if (body == nullptr)
5358 {
5359 Error error (lexer.peek_token ()->get_locus (),
5360 "could not parse definition in inherent impl %s definition",
5361 is_method ? "method" : "function");
5362 add_error (std::move (error));
5363
5364 skip_after_end_block ();
5365 return nullptr;
5366 }
5367
5368 // do actual if instead of ternary for return value optimisation
5369 if (is_method)
5370 {
5371 return std::unique_ptr<AST::Method> (
5372 new AST::Method (std::move (ident), std::move (qualifiers),
5373 std::move (generic_params), std::move (self_param),
5374 std::move (function_params), std::move (return_type),
5375 std::move (where_clause), std::move (body),
5376 std::move (vis), std::move (outer_attrs), locus));
5377 }
5378 else
5379 {
5380 return std::unique_ptr<AST::Function> (
5381 new AST::Function (std::move (ident), std::move (qualifiers),
5382 std::move (generic_params),
5383 std::move (function_params), std::move (return_type),
5384 std::move (where_clause), std::move (body),
5385 std::move (vis), std::move (outer_attrs), locus));
5386 }
5387}
5388
5389// Parses a single trait impl item (item inside a trait impl block).
5390template <typename ManagedTokenSource>
5391std::unique_ptr<AST::TraitImplItem>
5392Parser<ManagedTokenSource>::parse_trait_impl_item ()
5393{
5394 // parse outer attributes (if they exist)
5395 AST::AttrVec outer_attrs = parse_outer_attributes ();
5396
5397 // TODO: clean this function up, it is basically unreadable hacks
5398
5399 // branch on next token:
5400 const_TokenPtr t = lexer.peek_token ();
5401 switch (t->get_id ())
5402 {
5403 case IDENTIFIER:
5404 case SUPER:
5405 case SELF:
5406 case CRATE:
5407 case DOLLAR_SIGN:
5408 // these seem to be SimplePath tokens, so this is a macro invocation
5409 // semi
5410 return parse_macro_invocation_semi (std::move (outer_attrs));
5411 case TYPE:
5412 return parse_type_alias (AST::Visibility::create_private (),
5413 std::move (outer_attrs));
5414 case PUB: {
5415 // visibility, so not a macro invocation semi - must be constant,
5416 // function, or method
5417 AST::Visibility vis = parse_visibility ();
5418
5419 // TODO: is a recursive call to parse_trait_impl_item better?
5420 switch (lexer.peek_token ()->get_id ())
5421 {
5422 case TYPE:
5423 return parse_type_alias (std::move (vis), std::move (outer_attrs));
5424 case EXTERN_TOK:
5425 case UNSAFE:
5426 case FN_TOK:
5427 // function or method
5428 return parse_trait_impl_function_or_method (std::move (vis),
5429 std::move (
5430 outer_attrs));
5431 case CONST:
5432 // lookahead to resolve production - could be function/method or
5433 // const item
5434 t = lexer.peek_token (1);
5435
5436 switch (t->get_id ())
5437 {
5438 case IDENTIFIER:
5439 case UNDERSCORE:
5440 return parse_const_item (std::move (vis),
5441 std::move (outer_attrs));
5442 case UNSAFE:
5443 case EXTERN_TOK:
5444 case FN_TOK:
5445 return parse_trait_impl_function_or_method (std::move (vis),
5446 std::move (
5447 outer_attrs));
5448 default:
5449 add_error (Error (t->get_locus (),
5450 "unexpected token %qs in some sort of const "
5451 "item in trait impl",
5452 t->get_token_description ()));
5453
5454 lexer.skip_token (1); // TODO: is this right thing to do?
5455 return nullptr;
5456 }
5457 default:
5458 add_error (Error (t->get_locus (),
5459 "unrecognised token %qs for item in trait impl",
5460 t->get_token_description ()));
5461
5462 // skip?
5463 return nullptr;
5464 }
5465 }
5466 case EXTERN_TOK:
5467 case UNSAFE:
5468 case FN_TOK:
5469 // function or method
5470 return parse_trait_impl_function_or_method (
5471 AST::Visibility::create_private (), std::move (outer_attrs));
5472 case CONST:
5473 // lookahead to resolve production - could be function/method or const
5474 // item
5475 t = lexer.peek_token (1);
5476
5477 switch (t->get_id ())
5478 {
5479 case IDENTIFIER:
5480 case UNDERSCORE:
5481 return parse_const_item (AST::Visibility::create_private (),
5482 std::move (outer_attrs));
5483 case UNSAFE:
5484 case EXTERN_TOK:
5485 case FN_TOK:
5486 return parse_trait_impl_function_or_method (
5487 AST::Visibility::create_private (), std::move (outer_attrs));
5488 default:
5489 add_error (Error (
5490 t->get_locus (),
5491 "unexpected token %qs in some sort of const item in trait impl",
5492 t->get_token_description ()));
5493
5494 lexer.skip_token (1); // TODO: is this right thing to do?
5495 return nullptr;
5496 }
5497 gcc_unreachable ();
5498 default:
5499 add_error (Error (t->get_locus (),
5500 "unrecognised token %qs for item in trait impl",
5501 t->get_token_description ()));
5502
5503 // skip?
5504 return nullptr;
5505 }
5506}
5507
5508/* For internal use only by parse_trait_impl_item() - splits giant method into
5509 * smaller ones and prevents duplication of logic. Strictly, this parses a
5510 * function or method item inside a trait impl item block. */
5511template <typename ManagedTokenSource>
5512std::unique_ptr<AST::TraitImplItem>
5513Parser<ManagedTokenSource>::parse_trait_impl_function_or_method (
5514 AST::Visibility vis, AST::AttrVec outer_attrs)
5515{
5516 // this shares virtually all logic with
5517 // parse_inherent_impl_function_or_method
5518 // - template?
5519 Location locus = lexer.peek_token ()->get_locus ();
5520
5521 // parse function or method qualifiers
5522 AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
5523
5524 skip_token (FN_TOK);
5525
5526 // parse function or method name
5527 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5528 if (ident_tok == nullptr)
5529 {
5530 return nullptr;
5531 }
5532 Identifier ident = ident_tok->get_str ();
5533
5534 // DEBUG:
5535 rust_debug (
5536 "about to start parsing generic params in trait impl function or method");
5537
5538 // parse generic params
5539 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5540 = parse_generic_params_in_angles ();
5541
5542 // DEBUG:
5543 rust_debug (
5544 "finished parsing generic params in trait impl function or method");
5545
5546 if (!skip_token (LEFT_PAREN))
5547 {
5548 // skip after somewhere?
5549 return nullptr;
5550 }
5551
5552 // now for function vs method disambiguation - method has opening "self"
5553 // param
5554 AST::SelfParam self_param = parse_self_param ();
5555 // FIXME: ensure that self param doesn't accidently consume tokens for a
5556 // function
5557 bool is_method = false;
5558 if (!self_param.is_error ())
5559 {
5560 is_method = true;
5561
5562 // skip comma so function and method regular params can be parsed in
5563 // same way
5564 if (lexer.peek_token ()->get_id () == COMMA)
5565 {
5566 lexer.skip_token ();
5567 }
5568
5569 // DEBUG
5570 rust_debug ("successfully parsed self param in method trait impl item");
5571 }
5572
5573 // DEBUG
5574 rust_debug (
5575 "started to parse function params in function or method trait impl item");
5576
5577 // parse trait function params (only if next token isn't right paren)
5578 std::vector<AST::FunctionParam> function_params;
5579 if (lexer.peek_token ()->get_id () != RIGHT_PAREN)
5580 {
5581 function_params
5582 = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
5583
5584 if (function_params.empty ())
5585 {
5586 Error error (
5587 lexer.peek_token ()->get_locus (),
5588 "failed to parse function params in trait impl %s definition",
5589 is_method ? "method" : "function");
5590 add_error (std::move (error));
5591
5592 skip_after_next_block ();
5593 return nullptr;
5594 }
5595 }
5596
5597 // DEBUG
5598 rust_debug ("successfully parsed function params in function or method "
5599 "trait impl item");
5600
5601 if (!skip_token (RIGHT_PAREN))
5602 {
5603 skip_after_next_block ();
5604 return nullptr;
5605 }
5606
5607 // parse return type (optional)
5608 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
5609
5610 // DEBUG
5611 rust_debug (
5612 "successfully parsed return type in function or method trait impl item");
5613
5614 // parse where clause (optional)
5615 AST::WhereClause where_clause = parse_where_clause ();
5616
5617 // DEBUG
5618 rust_debug (
5619 "successfully parsed where clause in function or method trait impl item");
5620
5621 // parse function definition (in block) - semicolon not allowed
5622 if (lexer.peek_token ()->get_id () == SEMICOLON)
5623 {
5624 Error error (
5625 lexer.peek_token ()->get_locus (),
5626 "%s declaration in trait impl not allowed - must have a definition",
5627 is_method ? "method" : "function");
5628 add_error (std::move (error));
5629
5630 lexer.skip_token ();
5631 return nullptr;
5632 }
5633 std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
5634 if (body == nullptr)
5635 {
5636 Error error (lexer.peek_token ()->get_locus (),
5637 "could not parse definition in trait impl %s definition",
5638 is_method ? "method" : "function");
5639 add_error (std::move (error));
5640
5641 skip_after_end_block ();
5642 return nullptr;
5643 }
5644
5645 // do actual if instead of ternary for return value optimisation
5646 if (is_method)
5647 {
5648 return std::unique_ptr<AST::Method> (
5649 new AST::Method (std::move (ident), std::move (qualifiers),
5650 std::move (generic_params), std::move (self_param),
5651 std::move (function_params), std::move (return_type),
5652 std::move (where_clause), std::move (body),
5653 std::move (vis), std::move (outer_attrs), locus));
5654 }
5655 else
5656 {
5657 return std::unique_ptr<AST::Function> (
5658 new AST::Function (std::move (ident), std::move (qualifiers),
5659 std::move (generic_params),
5660 std::move (function_params), std::move (return_type),
5661 std::move (where_clause), std::move (body),
5662 std::move (vis), std::move (outer_attrs), locus));
5663 }
5664}
5665
5666// Parses an extern block of declarations.
5667template <typename ManagedTokenSource>
5668std::unique_ptr<AST::ExternBlock>
5669Parser<ManagedTokenSource>::parse_extern_block (AST::Visibility vis,
5670 AST::AttrVec outer_attrs)
5671{
5672 Location locus = lexer.peek_token ()->get_locus ();
5673 skip_token (EXTERN_TOK);
5674
5675 // detect optional abi name
5676 std::string abi;
5677 const_TokenPtr next_tok = lexer.peek_token ();
5678 if (next_tok->get_id () == STRING_LITERAL)
5679 {
5680 lexer.skip_token ();
5681 abi = next_tok->get_str ();
5682 }
5683
5684 if (!skip_token (LEFT_CURLY))
5685 {
5686 skip_after_end_block ();
5687 return nullptr;
5688 }
5689
5690 AST::AttrVec inner_attrs = parse_inner_attributes ();
5691
5692 // parse declarations inside extern block
5693 std::vector<std::unique_ptr<AST::ExternalItem>> extern_items;
5694
5695 const_TokenPtr t = lexer.peek_token ();
5696 while (t->get_id () != RIGHT_CURLY)
5697 {
5698 std::unique_ptr<AST::ExternalItem> extern_item = parse_external_item ();
5699
5700 if (extern_item == nullptr)
5701 {
5702 Error error (t->get_locus (),
5703 "failed to parse external item despite not reaching "
5704 "end of extern block");
5705 add_error (std::move (error));
5706
5707 return nullptr;
5708 }
5709
5710 extern_items.push_back (std::move (extern_item));
5711
5712 t = lexer.peek_token ();
5713 }
5714
5715 if (!skip_token (RIGHT_CURLY))
5716 {
5717 // skip somewhere
5718 return nullptr;
5719 }
5720
5721 extern_items.shrink_to_fit ();
5722
5723 return std::unique_ptr<AST::ExternBlock> (
5724 new AST::ExternBlock (std::move (abi), std::move (extern_items),
5725 std::move (vis), std::move (inner_attrs),
5726 std::move (outer_attrs), locus));
5727}
5728
5729// Parses a single extern block item (static or function declaration).
5730template <typename ManagedTokenSource>
5731std::unique_ptr<AST::ExternalItem>
5732Parser<ManagedTokenSource>::parse_external_item ()
5733{
5734 // parse optional outer attributes
5735 AST::AttrVec outer_attrs = parse_outer_attributes ();
5736
5737 Location locus = lexer.peek_token ()->get_locus ();
5738
5739 // parse optional visibility
5740 AST::Visibility vis = parse_visibility ();
5741
5742 const_TokenPtr t = lexer.peek_token ();
5743 switch (t->get_id ())
5744 {
5745 case IDENTIFIER:
5746 return parse_macro_invocation_semi (outer_attrs);
5747 case STATIC_TOK: {
5748 // parse extern static item
5749 lexer.skip_token ();
5750
5751 // parse mut (optional)
5752 bool has_mut = false;
5753 if (lexer.peek_token ()->get_id () == MUT)
5754 {
5755 lexer.skip_token ();
5756 has_mut = true;
5757 }
5758
5759 // parse identifier
5760 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5761 if (ident_tok == nullptr)
5762 {
5763 skip_after_semicolon ();
5764 return nullptr;
5765 }
5766 Identifier ident = ident_tok->get_str ();
5767
5768 if (!skip_token (COLON))
5769 {
5770 skip_after_semicolon ();
5771 return nullptr;
5772 }
5773
5774 // parse type (required)
5775 std::unique_ptr<AST::Type> type = parse_type ();
5776 if (type == nullptr)
5777 {
5778 Error error (lexer.peek_token ()->get_locus (),
5779 "failed to parse type in external static item");
5780 add_error (std::move (error));
5781
5782 skip_after_semicolon ();
5783 return nullptr;
5784 }
5785
5786 if (!skip_token (SEMICOLON))
5787 {
5788 // skip after somewhere?
5789 return nullptr;
5790 }
5791
5792 return std::unique_ptr<AST::ExternalStaticItem> (
5793 new AST::ExternalStaticItem (std::move (ident), std::move (type),
5794 has_mut, std::move (vis),
5795 std::move (outer_attrs), locus));
5796 }
5797 case FN_TOK: {
5798 // parse extern function declaration item
5799 // skip function token
5800 lexer.skip_token ();
5801
5802 // parse identifier
5803 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
5804 if (ident_tok == nullptr)
5805 {
5806 skip_after_semicolon ();
5807 return nullptr;
5808 }
5809 Identifier ident = ident_tok->get_str ();
5810
5811 // parse (optional) generic params
5812 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
5813 = parse_generic_params_in_angles ();
5814
5815 if (!skip_token (LEFT_PAREN))
5816 {
5817 skip_after_semicolon ();
5818 return nullptr;
5819 }
5820
5821 // parse parameters
5822 std::vector<AST::NamedFunctionParam> function_params;
5823 bool is_variadic = false;
5824 AST::AttrVec variadic_attrs;
5825
5826 const_TokenPtr t = lexer.peek_token ();
5827 while (t->get_id () != RIGHT_PAREN)
5828 {
5829 AST::AttrVec maybe_variadic_attrs = parse_outer_attributes ();
5830 if (lexer.peek_token ()->get_id () == ELLIPSIS)
5831 {
5832 // variadic - use attrs for this
5833 lexer.skip_token ();
5834 is_variadic = true;
5835 variadic_attrs = std::move (maybe_variadic_attrs);
5836 t = lexer.peek_token ();
5837
5838 if (t->get_id () != RIGHT_PAREN)
5839 {
5840 Error error (t->get_locus (),
5841 "expected right parentheses after variadic in "
5842 "named function "
5843 "parameters, found %qs",
5844 t->get_token_description ());
5845 add_error (std::move (error));
5846
5847 skip_after_semicolon ();
5848 return nullptr;
5849 }
5850
5851 break;
5852 }
5853
5854 AST::NamedFunctionParam param
5855 = parse_named_function_param (std::move (maybe_variadic_attrs));
5856 if (param.is_error ())
5857 {
5858 Error error (t->get_locus (), "could not parse named function "
5859 "parameter in external function");
5860 add_error (std::move (error));
5861
5862 skip_after_semicolon ();
5863 return nullptr;
5864 }
5865 function_params.push_back (std::move (param));
5866
5867 if (lexer.peek_token ()->get_id () != COMMA)
5868 break;
5869
5870 // skip comma
5871 lexer.skip_token ();
5872 t = lexer.peek_token ();
5873 }
5874
5875 if (!skip_token (RIGHT_PAREN))
5876 {
5877 skip_after_semicolon ();
5878 return nullptr;
5879 }
5880
5881 // parse (optional) return type
5882 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
5883
5884 // parse (optional) where clause
5885 AST::WhereClause where_clause = parse_where_clause ();
5886
5887 if (!skip_token (SEMICOLON))
5888 {
5889 // skip somewhere?
5890 return nullptr;
5891 }
5892
5893 function_params.shrink_to_fit ();
5894
5895 return std::unique_ptr<AST::ExternalFunctionItem> (
5896 new AST::ExternalFunctionItem (
5897 std::move (ident), std::move (generic_params),
5898 std::move (return_type), std::move (where_clause),
5899 std::move (function_params), is_variadic,
5900 std::move (variadic_attrs), std::move (vis),
5901 std::move (outer_attrs), locus));
5902 }
5903 default:
5904 // error
5905 add_error (
5906 Error (t->get_locus (),
5907 "unrecognised token %qs in extern block item declaration",
5908 t->get_token_description ()));
5909
5910 skip_after_semicolon ();
5911 return nullptr;
5912 }
5913}
5914
5915/* Parses an extern block function param (with "pattern" being _ or an
5916 * identifier). */
5917template <typename ManagedTokenSource>
5918AST::NamedFunctionParam
5919Parser<ManagedTokenSource>::parse_named_function_param (
5920 AST::AttrVec outer_attrs)
5921{
5922 // parse identifier/_
5923 std::string name;
5924
5925 const_TokenPtr t = lexer.peek_token ();
5926 Location name_location = t->get_locus ();
5927 switch (t->get_id ())
5928 {
5929 case IDENTIFIER:
5930 name = t->get_str ();
5931 lexer.skip_token ();
5932 break;
5933 case UNDERSCORE:
5934 name = "_";
5935 lexer.skip_token ();
5936 break;
5937 default:
5938 // this is not a function param, but not necessarily an error
5939 return AST::NamedFunctionParam::create_error ();
5940 }
5941
5942 if (!skip_token (COLON))
5943 {
5944 // skip after somewhere?
5945 return AST::NamedFunctionParam::create_error ();
5946 }
5947
5948 // parse (required) type
5949 std::unique_ptr<AST::Type> param_type = parse_type ();
5950 if (param_type == nullptr)
5951 {
5952 Error error (
5953 lexer.peek_token ()->get_locus (),
5954 "could not parse param type in extern block function declaration");
5955 add_error (std::move (error));
5956
5957 skip_after_semicolon ();
5958 return AST::NamedFunctionParam::create_error ();
5959 }
5960
5961 return AST::NamedFunctionParam (std::move (name), std::move (param_type),
5962 std::move (outer_attrs), name_location);
5963}
5964
5965// Parses a statement (will further disambiguate any statement).
5966template <typename ManagedTokenSource>
5967std::unique_ptr<AST::Stmt>
5968Parser<ManagedTokenSource>::parse_stmt (ParseRestrictions restrictions)
5969{
5970 // quick exit for empty statement
5971 // FIXME: Can we have empty statements without semicolons? Just nothing?
5972 const_TokenPtr t = lexer.peek_token ();
5973 if (t->get_id () == SEMICOLON)
5974 {
5975 lexer.skip_token ();
5976 return std::unique_ptr<AST::EmptyStmt> (
5977 new AST::EmptyStmt (t->get_locus ()));
5978 }
5979
5980 // parse outer attributes
5981 AST::AttrVec outer_attrs = parse_outer_attributes ();
5982
5983 // parsing this will be annoying because of the many different possibilities
5984 /* best may be just to copy paste in parse_item switch, and failing that try
5985 * to parse outer attributes, and then pass them in to either a let
5986 * statement or (fallback) expression statement. */
5987 // FIXME: think of a way to do this without such a large switch?
5988 t = lexer.peek_token ();
5989 switch (t->get_id ())
5990 {
5991 case LET:
5992 // let statement
5993 return parse_let_stmt (std::move (outer_attrs), restrictions);
5994 case PUB:
5995 case MOD:
5996 case EXTERN_TOK:
5997 case USE:
5998 case FN_TOK:
5999 case TYPE:
6000 case STRUCT_TOK:
6001 case ENUM_TOK:
6002 case CONST:
6003 case STATIC_TOK:
6004 case TRAIT:
6005 case IMPL:
6006 /* TODO: implement union keyword but not really because of
6007 * context-dependence crappy hack way to parse a union written below to
6008 * separate it from the good code. */
6009 // case UNION:
6010 case UNSAFE: // maybe - unsafe traits are a thing
6011 /* if any of these (should be all possible VisItem prefixes), parse a
6012 * VisItem can't parse item because would require reparsing outer
6013 * attributes */
6014 return parse_vis_item (std::move (outer_attrs));
6015 break;
6016 case SUPER:
6017 case SELF:
6018 case CRATE:
6019 case DOLLAR_SIGN:
6020 // almost certainly macro invocation semi
6021 return parse_macro_item (std::move (outer_attrs));
6022 break;
6023 // crappy hack to do union "keyword"
6024 case IDENTIFIER:
6025 if (t->get_str () == "union"
6026 && lexer.peek_token (1)->get_id () == IDENTIFIER)
6027 {
6028 return parse_vis_item (std::move (outer_attrs));
6029 // or should this go straight to parsing union?
6030 }
6031 else if (t->get_str () == "macro_rules")
6032 {
6033 // macro_rules! macro item
6034 return parse_macro_item (std::move (outer_attrs));
6035 }
6036 else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
6037 || lexer.peek_token (1)->get_id () == EXCLAM)
6038 {
6039 // FIXME: ensure doesn't take any expressions by mistake
6040 /* path (probably) or macro invocation, so probably a macro
6041 * invocation semi */
6042 return parse_macro_item (std::move (outer_attrs));
6043 }
6044 gcc_fallthrough ();
6045 // TODO: find out how to disable gcc "implicit fallthrough" warning
6046 default:
6047 // fallback: expression statement
6048 return parse_expr_stmt (std::move (outer_attrs), restrictions);
6049 break;
6050 }
6051}
6052
6053// Parses a let statement.
6054template <typename ManagedTokenSource>
6055std::unique_ptr<AST::LetStmt>
6056Parser<ManagedTokenSource>::parse_let_stmt (AST::AttrVec outer_attrs,
6057 ParseRestrictions restrictions)
6058{
6059 Location locus = lexer.peek_token ()->get_locus ();
6060 skip_token (LET);
6061
6062 // parse pattern (required)
6063 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
6064 if (pattern == nullptr)
6065 {
6066 Error error (lexer.peek_token ()->get_locus (),
6067 "failed to parse pattern in let statement");
6068 add_error (std::move (error));
6069
6070 skip_after_semicolon ();
6071 return nullptr;
6072 }
6073
6074 // parse type declaration (optional)
6075 std::unique_ptr<AST::Type> type = nullptr;
6076 if (lexer.peek_token ()->get_id () == COLON)
6077 {
6078 // must have a type declaration
6079 lexer.skip_token ();
6080
6081 type = parse_type ();
6082 if (type == nullptr)
6083 {
6084 Error error (lexer.peek_token ()->get_locus (),
6085 "failed to parse type in let statement");
6086 add_error (std::move (error));
6087
6088 skip_after_semicolon ();
6089 return nullptr;
6090 }
6091 }
6092
6093 // parse expression to set variable to (optional)
6094 std::unique_ptr<AST::Expr> expr = nullptr;
6095 if (lexer.peek_token ()->get_id () == EQUAL)
6096 {
6097 // must have an expression
6098 lexer.skip_token ();
6099
6100 expr = parse_expr ();
6101 if (expr == nullptr)
6102 {
6103 Error error (lexer.peek_token ()->get_locus (),
6104 "failed to parse expression in let statement");
6105 add_error (std::move (error));
6106
6107 skip_after_semicolon ();
6108 return nullptr;
6109 }
6110 }
6111
6112 if (restrictions.consume_semi)
6113 if (!skip_token (SEMICOLON))
6114 return nullptr;
6115
6116 return std::unique_ptr<AST::LetStmt> (
6117 new AST::LetStmt (std::move (pattern), std::move (expr), std::move (type),
6118 std::move (outer_attrs), locus));
6119}
6120
6121// Parses a type path.
6122template <typename ManagedTokenSource>
6123AST::TypePath
6124Parser<ManagedTokenSource>::parse_type_path ()
6125{
6126 bool has_opening_scope_resolution = false;
6127 Location locus = lexer.peek_token ()->get_locus ();
6128 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
6129 {
6130 has_opening_scope_resolution = true;
6131 lexer.skip_token ();
6132 }
6133
6134 // create segment vector
6135 std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
6136
6137 // parse required initial segment
6138 std::unique_ptr<AST::TypePathSegment> initial_segment
6139 = parse_type_path_segment ();
6140 if (initial_segment == nullptr)
6141 {
6142 // skip after somewhere?
6143 // don't necessarily throw error but yeah
6144 return AST::TypePath::create_error ();
6145 }
6146 segments.push_back (std::move (initial_segment));
6147
6148 // parse optional segments (as long as scope resolution operator exists)
6149 const_TokenPtr t = lexer.peek_token ();
6150 while (t->get_id () == SCOPE_RESOLUTION)
6151 {
6152 // skip scope resolution operator
6153 lexer.skip_token ();
6154
6155 // parse the actual segment - it is an error if it doesn't exist now
6156 std::unique_ptr<AST::TypePathSegment> segment
6157 = parse_type_path_segment ();
6158 if (segment == nullptr)
6159 {
6160 // skip after somewhere?
6161 Error error (t->get_locus (), "could not parse type path segment");
6162 add_error (std::move (error));
6163
6164 return AST::TypePath::create_error ();
6165 }
6166
6167 segments.push_back (std::move (segment));
6168
6169 t = lexer.peek_token ();
6170 }
6171
6172 segments.shrink_to_fit ();
6173
6174 return AST::TypePath (std::move (segments), locus,
6175 has_opening_scope_resolution);
6176}
6177
6178template <typename ManagedTokenSource>
6179AST::GenericArg
6180Parser<ManagedTokenSource>::parse_generic_arg ()
6181{
6182 auto tok = lexer.peek_token ();
6183 std::unique_ptr<AST::Expr> expr = nullptr;
6184
6185 switch (tok->get_id ())
6186 {
6187 case IDENTIFIER: {
6188 // This is a bit of a weird situation: With an identifier token, we
6189 // could either have a valid type or a macro (FIXME: anything else?). So
6190 // we need one bit of lookahead to differentiate if this is really
6191 auto next_tok = lexer.peek_token (1);
6192 if (next_tok->get_id () == EXCLAM)
6193 {
6194 auto type = parse_type ();
6195 if (type)
6196 return AST::GenericArg::create_type (std::move (type));
6197 else
6198 return AST::GenericArg::create_error ();
6199 }
6200 lexer.skip_token ();
6201 return AST::GenericArg::create_ambiguous (tok->get_str (),
6202 tok->get_locus ());
6203 }
6204 case LEFT_CURLY:
6205 expr = parse_block_expr ();
6206 break;
6207 case MINUS:
6208 case STRING_LITERAL:
6209 case CHAR_LITERAL:
6210 case INT_LITERAL:
6211 case FLOAT_LITERAL:
6212 case TRUE_LITERAL:
6213 case FALSE_LITERAL:
6214 expr = parse_literal_expr ();
6215 break;
6216 // FIXME: Because of this, error reporting is garbage for const generic
6217 // parameter's default values
6218 default: {
6219 auto type = parse_type ();
6220 // FIXME: Find a better way to do this?
6221 if (type)
6222 return AST::GenericArg::create_type (std::move (type));
6223 else
6224 return AST::GenericArg::create_error ();
6225 }
6226 }
6227
6228 if (!expr)
6229 return AST::GenericArg::create_error ();
6230
6231 return AST::GenericArg::create_const (std::move (expr));
6232}
6233
6234// Parses the generic arguments in each path segment.
6235template <typename ManagedTokenSource>
6236AST::GenericArgs
6237Parser<ManagedTokenSource>::parse_path_generic_args ()
6238{
6239 if (!skip_token (LEFT_ANGLE))
6240 {
6241 // skip after somewhere?
6242 return AST::GenericArgs::create_empty ();
6243 }
6244
6245 // We need to parse all lifetimes, then parse types and const generics in
6246 // any order.
6247
6248 // try to parse lifetimes first
6249 std::vector<AST::Lifetime> lifetime_args;
6250
6251 const_TokenPtr t = lexer.peek_token ();
6252 Location locus = t->get_locus ();
6253 while (!is_right_angle_tok (t->get_id ()))
6254 {
6255 AST::Lifetime lifetime = parse_lifetime ();
6256 if (lifetime.is_error ())
6257 {
6258 // not necessarily an error
6259 break;
6260 }
6261
6262 lifetime_args.push_back (std::move (lifetime));
6263
6264 // if next token isn't comma, then it must be end of list
6265 if (lexer.peek_token ()->get_id () != COMMA)
6266 {
6267 break;
6268 }
6269 // skip comma
6270 lexer.skip_token ();
6271
6272 t = lexer.peek_token ();
6273 }
6274
6275 // try to parse types and const generics second
6276 std::vector<AST::GenericArg> generic_args;
6277
6278 // TODO: think of better control structure
6279 t = lexer.peek_token ();
6280 while (!is_right_angle_tok (t->get_id ()))
6281 {
6282 // FIXME: Is it fine to break if there is one binding? Can't there be
6283 // bindings in between types?
6284
6285 // ensure not binding being parsed as type accidently
6286 if (t->get_id () == IDENTIFIER
6287 && lexer.peek_token (1)->get_id () == EQUAL)
6288 break;
6289
6290 auto arg = parse_generic_arg ();
6291 if (!arg.is_error ())
6292 {
6293 generic_args.emplace_back (std::move (arg));
6294 }
6295
6296 // FIXME: Do we need to break if we encounter an error?
6297
6298 // if next token isn't comma, then it must be end of list
6299 if (lexer.peek_token ()->get_id () != COMMA)
6300 break;
6301
6302 // skip comma
6303 lexer.skip_token ();
6304 t = lexer.peek_token ();
6305 }
6306
6307 // try to parse bindings third
6308 std::vector<AST::GenericArgsBinding> binding_args;
6309
6310 // TODO: think of better control structure
6311 t = lexer.peek_token ();
6312 while (!is_right_angle_tok (t->get_id ()))
6313 {
6314 AST::GenericArgsBinding binding = parse_generic_args_binding ();
6315 if (binding.is_error ())
6316 {
6317 // not necessarily an error
6318 break;
6319 }
6320
6321 binding_args.push_back (std::move (binding));
6322
6323 // if next token isn't comma, then it must be end of list
6324 if (lexer.peek_token ()->get_id () != COMMA)
6325 {
6326 break;
6327 }
6328 // skip comma
6329 lexer.skip_token ();
6330
6331 t = lexer.peek_token ();
6332 }
6333
6334 // skip any trailing commas
6335 if (lexer.peek_token ()->get_id () == COMMA)
6336 lexer.skip_token ();
6337
6338 if (!skip_generics_right_angle ())
6339 return AST::GenericArgs::create_empty ();
6340
6341 lifetime_args.shrink_to_fit ();
6342 generic_args.shrink_to_fit ();
6343 binding_args.shrink_to_fit ();
6344
6345 return AST::GenericArgs (std::move (lifetime_args), std::move (generic_args),
6346 std::move (binding_args), locus);
6347}
6348
6349// Parses a binding in a generic args path segment.
6350template <typename ManagedTokenSource>
6351AST::GenericArgsBinding
6352Parser<ManagedTokenSource>::parse_generic_args_binding ()
6353{
6354 const_TokenPtr ident_tok = lexer.peek_token ();
6355 if (ident_tok->get_id () != IDENTIFIER)
6356 {
6357 // allow non error-inducing use
6358 // skip somewhere?
6359 return AST::GenericArgsBinding::create_error ();
6360 }
6361 lexer.skip_token ();
6362 Identifier ident = ident_tok->get_str ();
6363
6364 if (!skip_token (EQUAL))
6365 {
6366 // skip after somewhere?
6367 return AST::GenericArgsBinding::create_error ();
6368 }
6369
6370 // parse type (required)
6371 std::unique_ptr<AST::Type> type = parse_type ();
6372 if (type == nullptr)
6373 {
6374 // skip somewhere?
6375 return AST::GenericArgsBinding::create_error ();
6376 }
6377
6378 return AST::GenericArgsBinding (std::move (ident), std::move (type),
6379 ident_tok->get_locus ());
6380}
6381
6382/* Parses a single type path segment (not including opening scope resolution,
6383 * but includes any internal ones). Includes generic args or type path
6384 * functions too. */
6385template <typename ManagedTokenSource>
6386std::unique_ptr<AST::TypePathSegment>
6387Parser<ManagedTokenSource>::parse_type_path_segment ()
6388{
6389 Location locus = lexer.peek_token ()->get_locus ();
6390 // parse ident segment part
6391 AST::PathIdentSegment ident_segment = parse_path_ident_segment ();
6392 if (ident_segment.is_error ())
6393 {
6394 // not necessarily an error
6395 return nullptr;
6396 }
6397
6398 /* lookahead to determine if variants exist - only consume scope resolution
6399 * then */
6400 bool has_separating_scope_resolution = false;
6401 const_TokenPtr next = lexer.peek_token (1);
6402 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
6403 && (next->get_id () == LEFT_ANGLE || next->get_id () == LEFT_PAREN))
6404 {
6405 has_separating_scope_resolution = true;
6406 lexer.skip_token ();
6407 }
6408
6409 // branch into variants on next token
6410 const_TokenPtr t = lexer.peek_token ();
6411 switch (t->get_id ())
6412 {
6413 case LEFT_ANGLE: {
6414 // parse generic args
6415 AST::GenericArgs generic_args = parse_path_generic_args ();
6416
6417 return std::unique_ptr<AST::TypePathSegmentGeneric> (
6418 new AST::TypePathSegmentGeneric (std::move (ident_segment),
6419 has_separating_scope_resolution,
6420 std::move (generic_args), locus));
6421 }
6422 case LEFT_PAREN: {
6423 // parse type path function
6424 AST::TypePathFunction type_path_function
6425 = parse_type_path_function (locus);
6426
6427 if (type_path_function.is_error ())
6428 {
6429 // skip after somewhere?
6430 return nullptr;
6431 }
6432
6433 return std::unique_ptr<AST::TypePathSegmentFunction> (
6434 new AST::TypePathSegmentFunction (std::move (ident_segment),
6435 has_separating_scope_resolution,
6436 std::move (type_path_function),
6437 locus));
6438 }
6439 default:
6440 // neither of them
6441 return std::unique_ptr<AST::TypePathSegment> (
6442 new AST::TypePathSegment (std::move (ident_segment),
6443 has_separating_scope_resolution, locus));
6444 }
6445 gcc_unreachable ();
6446}
6447
6448// Parses a function call representation inside a type path.
6449template <typename ManagedTokenSource>
6450AST::TypePathFunction
6451Parser<ManagedTokenSource>::parse_type_path_function (Location id_location)
6452{
6453 if (!skip_token (LEFT_PAREN))
6454 {
6455 // skip somewhere?
6456 return AST::TypePathFunction::create_error ();
6457 }
6458
6459 // parse function inputs
6460 std::vector<std::unique_ptr<AST::Type>> inputs;
6461
6462 while (lexer.peek_token ()->get_id () != RIGHT_PAREN)
6463 {
6464 std::unique_ptr<AST::Type> type = parse_type ();
6465 if (type == nullptr)
6466 {
6467 /* this is an error as there should've been a ')' there if there
6468 * wasn't a type */
6469 Error error (
6470 lexer.peek_token ()->get_locus (),
6471 "failed to parse type in parameters of type path function");
6472 add_error (std::move (error));
6473
6474 // skip somewhere?
6475 return AST::TypePathFunction::create_error ();
6476 }
6477
6478 inputs.push_back (std::move (type));
6479
6480 // skip commas, including trailing commas
6481 if (lexer.peek_token ()->get_id () != COMMA)
6482 break;
6483
6484 lexer.skip_token ();
6485 }
6486
6487 if (!skip_token (RIGHT_PAREN))
6488 {
6489 // skip somewhere?
6490 return AST::TypePathFunction::create_error ();
6491 }
6492
6493 // parse optional return type
6494 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
6495
6496 inputs.shrink_to_fit ();
6497 return AST::TypePathFunction (std::move (inputs), id_location,
6498 std::move (return_type));
6499}
6500
6501// Parses a path inside an expression that allows generic arguments.
6502template <typename ManagedTokenSource>
6503AST::PathInExpression
6504Parser<ManagedTokenSource>::parse_path_in_expression ()
6505{
6506 Location locus = Linemap::unknown_location ();
6507 bool has_opening_scope_resolution = false;
6508 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
6509 {
6510 has_opening_scope_resolution = true;
6511
6512 locus = lexer.peek_token ()->get_locus ();
6513
6514 lexer.skip_token ();
6515 }
6516
6517 // create segment vector
6518 std::vector<AST::PathExprSegment> segments;
6519
6520 if (locus == Linemap::unknown_location ())
6521 {
6522 locus = lexer.peek_token ()->get_locus ();
6523 }
6524
6525 // parse required initial segment
6526 AST::PathExprSegment initial_segment = parse_path_expr_segment ();
6527 if (initial_segment.is_error ())
6528 {
6529 // skip after somewhere?
6530 // don't necessarily throw error but yeah
6531 return AST::PathInExpression::create_error ();
6532 }
6533 segments.push_back (std::move (initial_segment));
6534
6535 // parse optional segments (as long as scope resolution operator exists)
6536 const_TokenPtr t = lexer.peek_token ();
6537 while (t->get_id () == SCOPE_RESOLUTION)
6538 {
6539 // skip scope resolution operator
6540 lexer.skip_token ();
6541
6542 // parse the actual segment - it is an error if it doesn't exist now
6543 AST::PathExprSegment segment = parse_path_expr_segment ();
6544 if (segment.is_error ())
6545 {
6546 // skip after somewhere?
6547 Error error (t->get_locus (),
6548 "could not parse path expression segment");
6549 add_error (std::move (error));
6550
6551 return AST::PathInExpression::create_error ();
6552 }
6553
6554 segments.push_back (std::move (segment));
6555
6556 t = lexer.peek_token ();
6557 }
6558
6559 segments.shrink_to_fit ();
6560
6561 return AST::PathInExpression (std::move (segments), {}, locus,
6562 has_opening_scope_resolution);
6563}
6564
6565/* Parses a single path in expression path segment (including generic
6566 * arguments). */
6567template <typename ManagedTokenSource>
6568AST::PathExprSegment
6569Parser<ManagedTokenSource>::parse_path_expr_segment ()
6570{
6571 Location locus = lexer.peek_token ()->get_locus ();
6572 // parse ident segment
6573 AST::PathIdentSegment ident = parse_path_ident_segment ();
6574 if (ident.is_error ())
6575 {
6576 // not necessarily an error?
6577 return AST::PathExprSegment::create_error ();
6578 }
6579
6580 // parse generic args (and turbofish), if they exist
6581 /* use lookahead to determine if they actually exist (don't want to
6582 * accidently parse over next ident segment) */
6583 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
6584 && lexer.peek_token (1)->get_id () == LEFT_ANGLE)
6585 {
6586 // skip scope resolution
6587 lexer.skip_token ();
6588
6589 AST::GenericArgs generic_args = parse_path_generic_args ();
6590
6591 return AST::PathExprSegment (std::move (ident), locus,
6592 std::move (generic_args));
6593 }
6594
6595 // return a generic parameter-less expr segment if not found
6596 return AST::PathExprSegment (std::move (ident), locus);
6597}
6598
6599/* Parses a fully qualified path in expression (i.e. a pattern). FIXME does
6600 * not parse outer attrs. */
6601template <typename ManagedTokenSource>
6602AST::QualifiedPathInExpression
6603Parser<ManagedTokenSource>::parse_qualified_path_in_expression (
6604 Location pratt_parsed_loc)
6605{
6606 /* Note: the Rust grammar is defined in such a way that it is impossible to
6607 * determine whether a prospective qualified path is a
6608 * QualifiedPathInExpression or QualifiedPathInType in all cases by the
6609 * rules themselves (the only possible difference is a TypePathSegment with
6610 * function, and lookahead to find this is too difficult). However, as this
6611 * is a pattern and QualifiedPathInType is a type, I believe it that their
6612 * construction will not be confused (due to rules regarding patterns vs
6613 * types).
6614 * As such, this function will not attempt to minimise errors created by
6615 * their confusion. */
6616
6617 // parse the qualified path type (required)
6618 AST::QualifiedPathType qual_path_type
6619 = parse_qualified_path_type (pratt_parsed_loc);
6620 if (qual_path_type.is_error ())
6621 {
6622 // TODO: should this create a parse error?
6623 return AST::QualifiedPathInExpression::create_error ();
6624 }
6625 Location locus = qual_path_type.get_locus ();
6626
6627 // parse path segments
6628 std::vector<AST::PathExprSegment> segments;
6629
6630 // parse initial required segment
6631 if (!expect_token (SCOPE_RESOLUTION))
6632 {
6633 // skip after somewhere?
6634
6635 return AST::QualifiedPathInExpression::create_error ();
6636 }
6637 AST::PathExprSegment initial_segment = parse_path_expr_segment ();
6638 if (initial_segment.is_error ())
6639 {
6640 // skip after somewhere?
6641 Error error (lexer.peek_token ()->get_locus (),
6642 "required initial path expression segment in "
6643 "qualified path in expression could not be parsed");
6644 add_error (std::move (error));
6645
6646 return AST::QualifiedPathInExpression::create_error ();
6647 }
6648 segments.push_back (std::move (initial_segment));
6649
6650 // parse optional segments (as long as scope resolution operator exists)
6651 const_TokenPtr t = lexer.peek_token ();
6652 while (t->get_id () == SCOPE_RESOLUTION)
6653 {
6654 // skip scope resolution operator
6655 lexer.skip_token ();
6656
6657 // parse the actual segment - it is an error if it doesn't exist now
6658 AST::PathExprSegment segment = parse_path_expr_segment ();
6659 if (segment.is_error ())
6660 {
6661 // skip after somewhere?
6662 Error error (t->get_locus (),
6663 "could not parse path expression segment in qualified "
6664 "path in expression");
6665 add_error (std::move (error));
6666
6667 return AST::QualifiedPathInExpression::create_error ();
6668 }
6669
6670 segments.push_back (std::move (segment));
6671
6672 t = lexer.peek_token ();
6673 }
6674
6675 segments.shrink_to_fit ();
6676
6677 // FIXME: outer attr parsing
6678 return AST::QualifiedPathInExpression (std::move (qual_path_type),
6679 std::move (segments), {}, locus);
6680}
6681
6682// Parses the type syntactical construction at the start of a qualified path.
6683template <typename ManagedTokenSource>
6684AST::QualifiedPathType
6685Parser<ManagedTokenSource>::parse_qualified_path_type (
6686 Location pratt_parsed_loc)
6687{
6688 Location locus = pratt_parsed_loc;
6689 /* TODO: should this actually be error? is there anywhere where this could
6690 * be valid? */
6691 if (locus == Linemap::unknown_location ())
6692 {
6693 locus = lexer.peek_token ()->get_locus ();
6694 if (!skip_token (LEFT_ANGLE))
6695 {
6696 // skip after somewhere?
6697 return AST::QualifiedPathType::create_error ();
6698 }
6699 }
6700
6701 // parse type (required)
6702 std::unique_ptr<AST::Type> type = parse_type ();
6703 if (type == nullptr)
6704 {
6705 Error error (lexer.peek_token ()->get_locus (),
6706 "could not parse type in qualified path type");
6707 add_error (std::move (error));
6708
6709 // skip somewhere?
6710 return AST::QualifiedPathType::create_error ();
6711 }
6712
6713 // parse optional as clause
6714 AST::TypePath as_type_path = AST::TypePath::create_error ();
6715 if (lexer.peek_token ()->get_id () == AS)
6716 {
6717 lexer.skip_token ();
6718
6719 // parse type path, which is required now
6720 as_type_path = parse_type_path ();
6721 if (as_type_path.is_error ())
6722 {
6723 Error error (
6724 lexer.peek_token ()->get_locus (),
6725 "could not parse type path in as clause in qualified path type");
6726 add_error (std::move (error));
6727
6728 // skip somewhere?
6729 return AST::QualifiedPathType::create_error ();
6730 }
6731 }
6732
6733 /* NOTE: should actually be a right-angle token, so
6734 * skip_generics_right_angle shouldn't be required */
6735 if (!skip_token (RIGHT_ANGLE))
6736 {
6737 // skip after somewhere?
6738 return AST::QualifiedPathType::create_error ();
6739 }
6740
6741 return AST::QualifiedPathType (std::move (type), locus,
6742 std::move (as_type_path));
6743}
6744
6745// Parses a fully qualified path in type (i.e. a type).
6746template <typename ManagedTokenSource>
6747AST::QualifiedPathInType
6748Parser<ManagedTokenSource>::parse_qualified_path_in_type ()
6749{
6750 Location locus = lexer.peek_token ()->get_locus ();
6751 // parse the qualified path type (required)
6752 AST::QualifiedPathType qual_path_type = parse_qualified_path_type ();
6753 if (qual_path_type.is_error ())
6754 {
6755 // TODO: should this create a parse error?
6756 return AST::QualifiedPathInType::create_error ();
6757 }
6758
6759 // parse initial required segment
6760 if (!expect_token (SCOPE_RESOLUTION))
6761 {
6762 // skip after somewhere?
6763
6764 return AST::QualifiedPathInType::create_error ();
6765 }
6766 std::unique_ptr<AST::TypePathSegment> initial_segment
6767 = parse_type_path_segment ();
6768 if (initial_segment == nullptr)
6769 {
6770 // skip after somewhere?
6771 Error error (lexer.peek_token ()->get_locus (),
6772 "required initial type path segment in qualified path in "
6773 "type could not be parsed");
6774 add_error (std::move (error));
6775
6776 return AST::QualifiedPathInType::create_error ();
6777 }
6778
6779 // parse optional segments (as long as scope resolution operator exists)
6780 std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
6781 const_TokenPtr t = lexer.peek_token ();
6782 while (t->get_id () == SCOPE_RESOLUTION)
6783 {
6784 // skip scope resolution operator
6785 lexer.skip_token ();
6786
6787 // parse the actual segment - it is an error if it doesn't exist now
6788 std::unique_ptr<AST::TypePathSegment> segment
6789 = parse_type_path_segment ();
6790 if (segment == nullptr)
6791 {
6792 // skip after somewhere?
6793 Error error (
6794 t->get_locus (),
6795 "could not parse type path segment in qualified path in type");
6796 add_error (std::move (error));
6797
6798 return AST::QualifiedPathInType::create_error ();
6799 }
6800
6801 segments.push_back (std::move (segment));
6802
6803 t = lexer.peek_token ();
6804 }
6805
6806 segments.shrink_to_fit ();
6807
6808 return AST::QualifiedPathInType (std::move (qual_path_type),
6809 std::move (initial_segment),
6810 std::move (segments), locus);
6811}
6812
6813// Parses a self param. Also handles self param not existing.
6814template <typename ManagedTokenSource>
6815AST::SelfParam
6816Parser<ManagedTokenSource>::parse_self_param ()
6817{
6818 bool has_reference = false;
6819 AST::Lifetime lifetime = AST::Lifetime::error ();
6820
6821 Location locus = lexer.peek_token ()->get_locus ();
6822
6823 // test if self is a reference parameter
6824 if (lexer.peek_token ()->get_id () == AMP)
6825 {
6826 has_reference = true;
6827 lexer.skip_token ();
6828
6829 // now test whether it has a lifetime
6830 if (lexer.peek_token ()->get_id () == LIFETIME)
6831 {
6832 lifetime = parse_lifetime ();
6833
6834 // something went wrong somehow
6835 if (lifetime.is_error ())
6836 {
6837 Error error (lexer.peek_token ()->get_locus (),
6838 "failed to parse lifetime in self param");
6839 add_error (std::move (error));
6840
6841 // skip after somewhere?
6842 return AST::SelfParam::create_error ();
6843 }
6844 }
6845 }
6846
6847 // test for mut
6848 bool has_mut = false;
6849 if (lexer.peek_token ()->get_id () == MUT)
6850 {
6851 has_mut = true;
6852 lexer.skip_token ();
6853 }
6854
6855 // skip self token
6856 const_TokenPtr self_tok = lexer.peek_token ();
6857 if (self_tok->get_id () != SELF)
6858 {
6859 // skip after somewhere?
6860 return AST::SelfParam::create_error ();
6861 }
6862 lexer.skip_token ();
6863
6864 // parse optional type
6865 std::unique_ptr<AST::Type> type = nullptr;
6866 if (lexer.peek_token ()->get_id () == COLON)
6867 {
6868 lexer.skip_token ();
6869
6870 // type is now required
6871 type = parse_type ();
6872 if (type == nullptr)
6873 {
6874 Error error (lexer.peek_token ()->get_locus (),
6875 "could not parse type in self param");
6876 add_error (std::move (error));
6877
6878 // skip after somewhere?
6879 return AST::SelfParam::create_error ();
6880 }
6881 }
6882
6883 // ensure that cannot have both type and reference
6884 if (type != nullptr && has_reference)
6885 {
6886 Error error (
6887 lexer.peek_token ()->get_locus (),
6888 "cannot have both a reference and a type specified in a self param");
6889 add_error (std::move (error));
6890
6891 // skip after somewhere?
6892 return AST::SelfParam::create_error ();
6893 }
6894
6895 if (has_reference)
6896 {
6897 return AST::SelfParam (std::move (lifetime), has_mut, locus);
6898 }
6899 else
6900 {
6901 // note that type may be nullptr here and that's fine
6902 return AST::SelfParam (std::move (type), has_mut, locus);
6903 }
6904}
32c8fb0e
JP
6905
6906/* Parses a method. Note that this function is probably useless because using
6907 * lookahead to determine whether a function is a method is a PITA (maybe not
6908 * even doable), so most places probably parse a "function or method" and then
6909 * resolve it into whatever it is afterward. As such, this is only here for
6910 * algorithmically defining the grammar rule. */
6911template <typename ManagedTokenSource>
6912AST::Method
6913Parser<ManagedTokenSource>::parse_method ()
6914{
6915 Location locus = lexer.peek_token ()->get_locus ();
6916 /* Note: as a result of the above, this will not attempt to disambiguate a
6917 * function parse qualifiers */
6918 AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
6919
6920 skip_token (FN_TOK);
6921
6922 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
6923 if (ident_tok == nullptr)
6924 {
6925 skip_after_next_block ();
6926 return AST::Method::create_error ();
6927 }
6928 Identifier method_name = ident_tok->get_str ();
6929
6930 // parse generic params - if exist
6931 std::vector<std::unique_ptr<AST::GenericParam>> generic_params
6932 = parse_generic_params_in_angles ();
6933
6934 if (!skip_token (LEFT_PAREN))
6935 {
6936 Error error (lexer.peek_token ()->get_locus (),
6937 "method missing opening parentheses before parameter list");
6938 add_error (std::move (error));
6939
6940 skip_after_next_block ();
6941 return AST::Method::create_error ();
6942 }
6943
6944 // parse self param
6945 AST::SelfParam self_param = parse_self_param ();
6946 if (self_param.is_error ())
6947 {
6948 Error error (lexer.peek_token ()->get_locus (),
6949 "could not parse self param in method");
6950 add_error (std::move (error));
6951
6952 skip_after_next_block ();
6953 return AST::Method::create_error ();
6954 }
6955
6956 // skip comma if it exists
6957 if (lexer.peek_token ()->get_id () == COMMA)
6958 lexer.skip_token ();
6959
6960 // parse function parameters
6961 std::vector<AST::FunctionParam> function_params
6962 = parse_function_params ([] (TokenId id) { return id == RIGHT_PAREN; });
6963
6964 if (!skip_token (RIGHT_PAREN))
6965 {
6966 Error error (lexer.peek_token ()->get_locus (),
6967 "method declaration missing closing parentheses after "
6968 "parameter list");
6969 add_error (std::move (error));
6970
6971 skip_after_next_block ();
6972 return AST::Method::create_error ();
6973 }
6974
6975 // parse function return type - if exists
6976 std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
6977
6978 // parse where clause - if exists
6979 AST::WhereClause where_clause = parse_where_clause ();
6980
6981 // parse block expression
6982 std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
6983 if (block_expr == nullptr)
6984 {
6985 Error error (lexer.peek_token ()->get_locus (),
6986 "method declaration missing block expression");
6987 add_error (std::move (error));
6988
6989 skip_after_end_block ();
6990 return AST::Method::create_error ();
6991 }
6992
6993 // does not parse visibility, but this method isn't used, so doesn't matter
6994 return AST::Method (std::move (method_name), std::move (qualifiers),
6995 std::move (generic_params), std::move (self_param),
6996 std::move (function_params), std::move (return_type),
6997 std::move (where_clause), std::move (block_expr),
6998 AST::Visibility::create_error (), AST::AttrVec (), locus);
6999}
7000
7001/* Parses an expression statement (disambiguates to expression with or without
7002 * block statement). */
7003template <typename ManagedTokenSource>
7004std::unique_ptr<AST::ExprStmt>
7005Parser<ManagedTokenSource>::parse_expr_stmt (AST::AttrVec outer_attrs,
7006 ParseRestrictions restrictions)
7007{
7008 /* potential thoughts - define new virtual method "has_block()" on expr.
7009 * parse expr and then determine whether semicolon is needed as a result of
7010 * this method. but then this would require dynamic_cast, which is not
7011 * allowed. */
7012
7013 /* okay new thought - big switch to disambiguate exprs with blocks - either
7014 * block expr, async block expr, unsafe block expr, loop expr, if expr, if
7015 * let expr, or match expr. So all others are exprs without block. */
7016 /* new thought: possible initial tokens: 'loop', 'while', 'for', lifetime
7017 * (and then ':' and then loop), 'if', 'match', '{', 'async', 'unsafe' (and
7018 * then
7019 * '{')). This seems to have no ambiguity. */
7020
7021 const_TokenPtr t = lexer.peek_token ();
7022 /* TODO: should the switch just directly call the individual parse methods
7023 * rather than adding another layer of indirection with
7024 * parse_expr_stmt_with_block()? */
7025 switch (t->get_id ())
7026 {
7027 case LOOP:
7028 case WHILE:
7029 case FOR:
7030 case IF:
7031 case MATCH_TOK:
7032 case LEFT_CURLY:
7033 case ASYNC:
7034 // expression with block
7035 return parse_expr_stmt_with_block (std::move (outer_attrs));
7036 case LIFETIME: {
7037 /* FIXME: are there any expressions without blocks that can have
7038 * lifetime as their first token? Or is loop expr the only one? */
7039 // safe side for now:
7040 if (lexer.peek_token (1)->get_id () == COLON
7041 && lexer.peek_token (2)->get_id () == LOOP)
7042 {
7043 return parse_expr_stmt_with_block (std::move (outer_attrs));
7044 }
7045 else
7046 {
7047 return parse_expr_stmt_without_block (std::move (outer_attrs),
7048 restrictions);
7049 }
7050 }
7051 case UNSAFE: {
7052 /* FIXME: are there any expressions without blocks that can have
7053 * unsafe as their first token? Or is unsafe the only one? */
7054 // safe side for now
7055 if (lexer.peek_token (1)->get_id () == LEFT_CURLY)
7056 {
7057 return parse_expr_stmt_with_block (std::move (outer_attrs));
7058 }
7059 else
7060 {
7061 return parse_expr_stmt_without_block (std::move (outer_attrs),
7062 restrictions);
7063 }
7064 }
7065 default:
7066 // not a parse expr with block, so must be expr without block
7067 /* TODO: if possible, be more selective about possible expr without
7068 * block initial tokens in order to prevent more syntactical errors at
7069 * parse time. */
7070 return parse_expr_stmt_without_block (std::move (outer_attrs),
7071 restrictions);
7072 }
7073}
7074
7075template <typename ManagedTokenSource>
7076std::unique_ptr<AST::ExprWithBlock>
7077Parser<ManagedTokenSource>::parse_expr_with_block (AST::AttrVec outer_attrs)
7078{
7079 std::unique_ptr<AST::ExprWithBlock> expr_parsed = nullptr;
7080
7081 const_TokenPtr t = lexer.peek_token ();
7082 switch (t->get_id ())
7083 {
7084 case IF:
7085 // if or if let, so more lookahead to find out
7086 if (lexer.peek_token (1)->get_id () == LET)
7087 {
7088 // if let expr
7089 expr_parsed = parse_if_let_expr (std::move (outer_attrs));
7090 break;
7091 }
7092 else
7093 {
7094 // if expr
7095 expr_parsed = parse_if_expr (std::move (outer_attrs));
7096 break;
7097 }
7098 case LOOP:
7099 // infinite loop
7100 expr_parsed = parse_loop_expr (std::move (outer_attrs));
7101 break;
7102 case FOR:
7103 // "for" iterator loop
7104 expr_parsed = parse_for_loop_expr (std::move (outer_attrs));
7105 break;
7106 case WHILE: {
7107 // while or while let, so more lookahead to find out
7108 if (lexer.peek_token (1)->get_id () == LET)
7109 {
7110 // while let loop expr
7111 expr_parsed = parse_while_let_loop_expr (std::move (outer_attrs));
7112 break;
7113 }
7114 else
7115 {
7116 // while loop expr
7117 expr_parsed = parse_while_loop_expr (std::move (outer_attrs));
7118 break;
7119 }
7120 }
7121 case MATCH_TOK:
7122 // match expression
7123 expr_parsed = parse_match_expr (std::move (outer_attrs));
7124 break;
7125 case LEFT_CURLY:
7126 // block expression
7127 expr_parsed = parse_block_expr (std::move (outer_attrs));
7128 break;
7129 case ASYNC:
7130 // async block expression
7131 expr_parsed = parse_async_block_expr (std::move (outer_attrs));
7132 break;
7133 case UNSAFE:
7134 // unsafe block expression
7135 expr_parsed = parse_unsafe_block_expr (std::move (outer_attrs));
7136 break;
7137 case LIFETIME:
7138 // some kind of loop expr (with loop label)
7139 expr_parsed = parse_labelled_loop_expr (std::move (outer_attrs));
7140 break;
7141 default:
7142 add_error (Error (
7143 t->get_locus (),
7144 "could not recognise expr beginning with %qs as an expr with block in"
7145 " parsing expr statement",
7146 t->get_token_description ()));
7147
7148 skip_after_next_block ();
7149 return nullptr;
7150 }
7151
7152 // ensure expr parsed exists
7153 if (expr_parsed == nullptr)
7154 {
7155 Error error (t->get_locus (),
7156 "failed to parse expr with block in parsing expr statement");
7157 add_error (std::move (error));
7158
7159 skip_after_end_block ();
7160 return nullptr;
7161 }
7162
7163 return expr_parsed;
7164}
7165
7166/* Parses a expression statement containing an expression with block.
7167 * Disambiguates internally. */
7168template <typename ManagedTokenSource>
7169std::unique_ptr<AST::ExprStmtWithBlock>
7170Parser<ManagedTokenSource>::parse_expr_stmt_with_block (
7171 AST::AttrVec outer_attrs)
7172{
7173 auto expr_parsed = parse_expr_with_block (std::move (outer_attrs));
7174 auto locus = expr_parsed->get_locus ();
7175
7176 // return expr stmt created from expr
7177 return std::unique_ptr<AST::ExprStmtWithBlock> (
7178 new AST::ExprStmtWithBlock (std::move (expr_parsed), locus,
7179 lexer.peek_token ()->get_id () == SEMICOLON));
7180}
7181
7182/* Parses an expression statement containing an expression without block.
7183 * Disambiguates further. */
7184template <typename ManagedTokenSource>
7185std::unique_ptr<AST::ExprStmtWithoutBlock>
7186Parser<ManagedTokenSource>::parse_expr_stmt_without_block (
7187 AST::AttrVec outer_attrs, ParseRestrictions restrictions)
7188{
7189 /* TODO: maybe move more logic for expr without block in here for better
7190 * error handling */
7191
7192 // attempt to parse via parse_expr_without_block - seems to work
7193 std::unique_ptr<AST::ExprWithoutBlock> expr = nullptr;
7194 Location locus = lexer.peek_token ()->get_locus ();
7195
7196 restrictions.expr_can_be_stmt = true;
7197
7198 expr = parse_expr_without_block (std::move (outer_attrs), restrictions);
7199 if (expr == nullptr)
7200 {
7201 // expr is required, error
7202 Error error (lexer.peek_token ()->get_locus (),
7203 "failed to parse expr without block in expr statement");
7204 add_error (std::move (error));
7205
7206 skip_after_semicolon ();
7207 return nullptr;
7208 }
7209
7210 if (restrictions.consume_semi)
7211 if (!skip_token (SEMICOLON))
7212 return nullptr;
7213
7214 return std::unique_ptr<AST::ExprStmtWithoutBlock> (
7215 new AST::ExprStmtWithoutBlock (std::move (expr), locus));
7216}
7217
7218/* Parses an expression without a block associated with it (further
7219 * disambiguates). */
7220template <typename ManagedTokenSource>
7221std::unique_ptr<AST::ExprWithoutBlock>
7222Parser<ManagedTokenSource>::parse_expr_without_block (
7223 AST::AttrVec outer_attrs, ParseRestrictions restrictions)
7224{
7225 /* Notes on types of expr without block:
7226 * - literal expr tokens that are literals
7227 * - path expr path_in_expr or qual_path_in_expr
7228 * - operator expr many different types
7229 * unary:
7230 * borrow expr ( '&' | '&&' ) 'mut'? expr
7231 * dereference expr '*' expr
7232 * error propagation expr '?'
7233 * negation '-' expr
7234 * not '!' expr
7235 * binary: all start with expr
7236 * - grouped/paren expr '(' inner_attributes expr ')'
7237 * - array expr '[' inner_attributes array_elems? ']'
7238 * - await expr expr '.' 'await'
7239 * - (array/slice) index expr expr '[' expr ']'
7240 * - tuple expr '(' inner_attributes tuple_elems? ')'
7241 * note that a single elem tuple is distinguished from a grouped expr
7242 * by a trailing comma, i.e. a grouped expr is preferred over a tuple expr
7243 * - tuple index expr expr '.' tuple_index
7244 * - struct expr path_in_expr (and optional other stuff)
7245 * - enum variant expr path_in_expr (and optional other stuff)
7246 * this means that there is no syntactic difference between an enum
7247 * variant and a struct
7248 * - only name resolution can tell the difference. Thus, maybe rework
7249 * AST to take this into account ("struct or enum" nodes?)
7250 * - (function) call expr expr '(' call_params? ')'
7251 * - method call expr expr '.' path_expr_segment '(' call_params? ')'
7252 * - field expr expr '.' identifier
7253 * note that method call expr is preferred, i.e. field expr must not be
7254 * followed by parenthesised expression sequence.
7255 * - closure expr 'move'? ( '||' | '|' closure_params? '|' ) (
7256 * expr | '->' type_no_bounds block_expr )
7257 * - continue expr 'continue' labelled_lifetime?
7258 * - break expr 'break' labelled_lifetime? expr?
7259 * - range expr many different types but all involve '..' or
7260 * '..='
7261 * - return expr 'return' as 1st tok
7262 * - macro invocation identifier then :: or identifier then !
7263 * (simple_path '!')
7264 *
7265 * any that have rules beginning with 'expr' should probably be
7266 * pratt-parsed,
7267 * with parsing type to use determined by token AND lookahead. */
7268
7269 // ok well at least can do easy ones
7270 const_TokenPtr t = lexer.peek_token ();
7271 switch (t->get_id ())
7272 {
7273 case RETURN_TOK:
7274 // return expr
7275 return parse_return_expr (std::move (outer_attrs));
7276 case BREAK:
7277 // break expr
7278 return parse_break_expr (std::move (outer_attrs));
7279 case CONTINUE:
7280 // continue expr
7281 return parse_continue_expr (std::move (outer_attrs));
7282 case MOVE:
7283 // closure expr (though not all closure exprs require this)
7284 return parse_closure_expr (std::move (outer_attrs));
7285 case LEFT_SQUARE:
7286 // array expr (creation, not index)
7287 return parse_array_expr (std::move (outer_attrs));
7288 default: {
7289 /* HACK: piggyback on pratt parsed expr and abuse polymorphism to
7290 * essentially downcast */
7291
7292 std::unique_ptr<AST::Expr> expr
7293 = parse_expr (std::move (outer_attrs), restrictions);
7294
7295 if (expr == nullptr)
7296 {
7297 Error error (t->get_locus (),
7298 "failed to parse expression for expression without "
7299 "block (pratt-parsed expression is null)");
7300 add_error (std::move (error));
7301
7302 return nullptr;
7303 }
7304
7305 std::unique_ptr<AST::ExprWithoutBlock> expr_without_block (
7306 expr->as_expr_without_block ());
7307
7308 if (expr_without_block != nullptr)
7309 {
7310 return expr_without_block;
7311 }
7312 else
7313 {
7314 Error error (t->get_locus (),
7315 "converted expr without block is null");
7316 add_error (std::move (error));
7317
7318 return nullptr;
7319 }
7320 }
7321 }
7322}
7323
7324// Parses a block expression, including the curly braces at start and end.
7325template <typename ManagedTokenSource>
7326std::unique_ptr<AST::BlockExpr>
7327Parser<ManagedTokenSource>::parse_block_expr (AST::AttrVec outer_attrs,
7328 Location pratt_parsed_loc)
7329{
7330 Location locus = pratt_parsed_loc;
7331 if (locus == Linemap::unknown_location ())
7332 {
7333 locus = lexer.peek_token ()->get_locus ();
7334 if (!skip_token (LEFT_CURLY))
7335 {
7336 skip_after_end_block ();
7337 return nullptr;
7338 }
7339 }
7340
7341 AST::AttrVec inner_attrs = parse_inner_attributes ();
7342
7343 // parse statements and expression
7344 std::vector<std::unique_ptr<AST::Stmt>> stmts;
7345 std::unique_ptr<AST::Expr> expr = nullptr;
7346
7347 const_TokenPtr t = lexer.peek_token ();
7348 while (t->get_id () != RIGHT_CURLY)
7349 {
7350 ExprOrStmt expr_or_stmt = parse_stmt_or_expr_without_block ();
7351 if (expr_or_stmt.is_error ())
7352 {
7353 Error error (t->get_locus (),
7354 "failed to parse statement or expression without "
7355 "block in block expression");
7356 add_error (std::move (error));
7357
7358 return nullptr;
7359 }
7360
7361 t = lexer.peek_token ();
7362
7363 if (expr_or_stmt.stmt != nullptr)
7364 {
7365 stmts.push_back (std::move (expr_or_stmt.stmt));
7366 }
7367 else
7368 {
7369 // assign to expression and end parsing inside
7370 expr = std::move (expr_or_stmt.expr);
7371 break;
7372 }
7373 }
7374
7375 Location end_locus = t->get_locus ();
7376
7377 if (!skip_token (RIGHT_CURLY))
7378 {
7379 Error error (t->get_locus (),
7380 "error may be from having an expression (as opposed to "
7381 "statement) in the body of the function but not last");
7382 add_error (std::move (error));
7383
7384 skip_after_end_block ();
7385 return nullptr;
7386 }
7387
7388 // grammar allows for empty block expressions
7389
7390 stmts.shrink_to_fit ();
7391
7392 return std::unique_ptr<AST::BlockExpr> (
7393 new AST::BlockExpr (std::move (stmts), std::move (expr),
7394 std::move (inner_attrs), std::move (outer_attrs), locus,
7395 end_locus));
7396}
7397
7398/* Parses a "grouped" expression (expression in parentheses), used to control
7399 * precedence. */
7400template <typename ManagedTokenSource>
7401std::unique_ptr<AST::GroupedExpr>
7402Parser<ManagedTokenSource>::parse_grouped_expr (AST::AttrVec outer_attrs)
7403{
7404 Location locus = lexer.peek_token ()->get_locus ();
7405 skip_token (LEFT_PAREN);
7406
7407 AST::AttrVec inner_attrs = parse_inner_attributes ();
7408
7409 // parse required expr inside parentheses
7410 std::unique_ptr<AST::Expr> expr_in_parens = parse_expr ();
7411 if (expr_in_parens == nullptr)
7412 {
7413 // skip after somewhere?
7414 // error?
7415 return nullptr;
7416 }
7417
7418 if (!skip_token (RIGHT_PAREN))
7419 {
7420 // skip after somewhere?
7421 return nullptr;
7422 }
7423
7424 return std::unique_ptr<AST::GroupedExpr> (
7425 new AST::GroupedExpr (std::move (expr_in_parens), std::move (inner_attrs),
7426 std::move (outer_attrs), locus));
7427}
7428
7429// Parses a closure expression (closure definition).
7430template <typename ManagedTokenSource>
7431std::unique_ptr<AST::ClosureExpr>
7432Parser<ManagedTokenSource>::parse_closure_expr (AST::AttrVec outer_attrs)
7433{
7434 Location locus = lexer.peek_token ()->get_locus ();
7435 // detect optional "move"
7436 bool has_move = false;
7437 if (lexer.peek_token ()->get_id () == MOVE)
7438 {
7439 lexer.skip_token ();
7440 has_move = true;
7441 }
7442
7443 // handle parameter list
7444 std::vector<AST::ClosureParam> params;
7445
7446 const_TokenPtr t = lexer.peek_token ();
7447 switch (t->get_id ())
7448 {
7449 case OR:
7450 // skip token, no parameters
7451 lexer.skip_token ();
7452 break;
7453 case PIPE:
7454 // actually may have parameters
7455 lexer.skip_token ();
7456
7457 while (t->get_id () != PIPE)
7458 {
7459 AST::ClosureParam param = parse_closure_param ();
7460 if (param.is_error ())
7461 {
7462 // TODO is this really an error?
7463 Error error (t->get_locus (), "could not parse closure param");
7464 add_error (std::move (error));
7465
7466 break;
7467 }
7468 params.push_back (std::move (param));
7469
7470 if (lexer.peek_token ()->get_id () != COMMA)
7471 {
7472 // not an error but means param list is done
7473 break;
7474 }
7475 // skip comma
7476 lexer.skip_token ();
7477
7478 t = lexer.peek_token ();
7479 }
7480 params.shrink_to_fit ();
7481 break;
7482 default:
7483 add_error (Error (t->get_locus (),
7484 "unexpected token %qs in closure expression - expected "
7485 "%<|%> or %<||%>",
7486 t->get_token_description ()));
7487
7488 // skip somewhere?
7489 return nullptr;
7490 }
7491
7492 // again branch based on next token
7493 t = lexer.peek_token ();
7494 if (t->get_id () == RETURN_TYPE)
7495 {
7496 // must be return type closure with block expr
7497
7498 // skip "return type" token
7499 lexer.skip_token ();
7500
7501 // parse actual type, which is required
7502 std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
7503 if (type == nullptr)
7504 {
7505 // error
7506 Error error (t->get_locus (), "failed to parse type for closure");
7507 add_error (std::move (error));
7508
7509 // skip somewhere?
7510 return nullptr;
7511 }
7512
7513 // parse block expr, which is required
7514 std::unique_ptr<AST::BlockExpr> block = parse_block_expr ();
7515 if (block == nullptr)
7516 {
7517 // error
7518 Error error (lexer.peek_token ()->get_locus (),
7519 "failed to parse block expr in closure");
7520 add_error (std::move (error));
7521
7522 // skip somewhere?
7523 return nullptr;
7524 }
7525
7526 return std::unique_ptr<AST::ClosureExprInnerTyped> (
7527 new AST::ClosureExprInnerTyped (std::move (type), std::move (block),
7528 std::move (params), locus, has_move,
7529 std::move (outer_attrs)));
7530 }
7531 else
7532 {
7533 // must be expr-only closure
7534
7535 // parse expr, which is required
7536 std::unique_ptr<AST::Expr> expr = parse_expr ();
7537 if (expr == nullptr)
7538 {
7539 Error error (t->get_locus (),
7540 "failed to parse expression in closure");
7541 add_error (std::move (error));
7542
7543 // skip somewhere?
7544 return nullptr;
7545 }
7546
7547 return std::unique_ptr<AST::ClosureExprInner> (
7548 new AST::ClosureExprInner (std::move (expr), std::move (params), locus,
7549 has_move, std::move (outer_attrs)));
7550 }
7551}
7552
7553// Parses a literal token (to literal expression).
7554template <typename ManagedTokenSource>
7555std::unique_ptr<AST::LiteralExpr>
7556Parser<ManagedTokenSource>::parse_literal_expr (AST::AttrVec outer_attrs)
7557{
7558 // TODO: change if literal representation in lexer changes
7559
7560 std::string literal_value;
7561 AST::Literal::LitType type = AST::Literal::STRING;
7562
7563 // branch based on token
7564 const_TokenPtr t = lexer.peek_token ();
7565 switch (t->get_id ())
7566 {
7567 case CHAR_LITERAL:
7568 type = AST::Literal::CHAR;
7569 literal_value = t->get_str ();
7570 lexer.skip_token ();
7571 break;
7572 case STRING_LITERAL:
7573 type = AST::Literal::STRING;
7574 literal_value = t->get_str ();
7575 lexer.skip_token ();
7576 break;
7577 case BYTE_CHAR_LITERAL:
7578 type = AST::Literal::BYTE;
7579 literal_value = t->get_str ();
7580 lexer.skip_token ();
7581 break;
7582 case BYTE_STRING_LITERAL:
7583 type = AST::Literal::BYTE_STRING;
7584 literal_value = t->get_str ();
7585 lexer.skip_token ();
7586 break;
7587 case INT_LITERAL:
7588 type = AST::Literal::INT;
7589 literal_value = t->get_str ();
7590 lexer.skip_token ();
7591 break;
7592 case FLOAT_LITERAL:
7593 type = AST::Literal::FLOAT;
7594 literal_value = t->get_str ();
7595 lexer.skip_token ();
7596 break;
7597 // case BOOL_LITERAL
7598 // use true and false keywords rather than "bool literal" Rust terminology
7599 case TRUE_LITERAL:
7600 type = AST::Literal::BOOL;
7601 literal_value = "true";
7602 lexer.skip_token ();
7603 break;
7604 case FALSE_LITERAL:
7605 type = AST::Literal::BOOL;
7606 literal_value = "false";
7607 lexer.skip_token ();
7608 break;
7609 default:
7610 // error - cannot be a literal expr
7611 add_error (Error (t->get_locus (),
7612 "unexpected token %qs when parsing literal expression",
7613 t->get_token_description ()));
7614
7615 // skip?
7616 return nullptr;
7617 }
7618
7619 // create literal based on stuff in switch
7620 return std::unique_ptr<AST::LiteralExpr> (
7621 new AST::LiteralExpr (std::move (literal_value), std::move (type),
7622 t->get_type_hint (), std::move (outer_attrs),
7623 t->get_locus ()));
7624}
7625
7626// Parses a return expression (including any expression to return).
7627template <typename ManagedTokenSource>
7628std::unique_ptr<AST::ReturnExpr>
7629Parser<ManagedTokenSource>::parse_return_expr (AST::AttrVec outer_attrs,
7630 Location pratt_parsed_loc)
7631{
7632 Location locus = pratt_parsed_loc;
7633 if (locus == Linemap::unknown_location ())
7634 {
7635 locus = lexer.peek_token ()->get_locus ();
7636 skip_token (RETURN_TOK);
7637 }
7638
7639 // parse expression to return, if it exists
7640 ParseRestrictions restrictions;
7641 restrictions.expr_can_be_null = true;
7642 std::unique_ptr<AST::Expr> returned_expr
7643 = parse_expr (AST::AttrVec (), restrictions);
7644
7645 return std::unique_ptr<AST::ReturnExpr> (
7646 new AST::ReturnExpr (std::move (returned_expr), std::move (outer_attrs),
7647 locus));
7648}
7649
7650/* Parses a break expression (including any label to break to AND any return
7651 * expression). */
7652template <typename ManagedTokenSource>
7653std::unique_ptr<AST::BreakExpr>
7654Parser<ManagedTokenSource>::parse_break_expr (AST::AttrVec outer_attrs,
7655 Location pratt_parsed_loc)
7656{
7657 Location locus = pratt_parsed_loc;
7658 if (locus == Linemap::unknown_location ())
7659 {
7660 locus = lexer.peek_token ()->get_locus ();
7661 skip_token (BREAK);
7662 }
7663
7664 // parse label (lifetime) if it exists - create dummy first
7665 AST::Lifetime label = AST::Lifetime::error ();
7666 if (lexer.peek_token ()->get_id () == LIFETIME)
7667 {
7668 label = parse_lifetime ();
7669 }
7670
7671 // parse break return expression if it exists
7672 ParseRestrictions restrictions;
7673 restrictions.expr_can_be_null = true;
7674 std::unique_ptr<AST::Expr> return_expr
7675 = parse_expr (AST::AttrVec (), restrictions);
7676
7677 return std::unique_ptr<AST::BreakExpr> (
7678 new AST::BreakExpr (std::move (label), std::move (return_expr),
7679 std::move (outer_attrs), locus));
7680}
7681
7682// Parses a continue expression (including any label to continue from).
7683template <typename ManagedTokenSource>
7684std::unique_ptr<AST::ContinueExpr>
7685Parser<ManagedTokenSource>::parse_continue_expr (AST::AttrVec outer_attrs,
7686 Location pratt_parsed_loc)
7687{
7688 Location locus = pratt_parsed_loc;
7689 if (locus == Linemap::unknown_location ())
7690 {
7691 locus = lexer.peek_token ()->get_locus ();
7692 skip_token (CONTINUE);
7693 }
7694
7695 // parse label (lifetime) if it exists - create dummy first
7696 AST::Lifetime label = AST::Lifetime::error ();
7697 if (lexer.peek_token ()->get_id () == LIFETIME)
7698 {
7699 label = parse_lifetime ();
7700 }
7701
7702 return std::unique_ptr<AST::ContinueExpr> (
7703 new AST::ContinueExpr (std::move (label), std::move (outer_attrs), locus));
7704}
7705
7706// Parses a loop label used in loop expressions.
7707template <typename ManagedTokenSource>
7708AST::LoopLabel
7709Parser<ManagedTokenSource>::parse_loop_label ()
7710{
7711 // parse lifetime - if doesn't exist, assume no label
7712 const_TokenPtr t = lexer.peek_token ();
7713 if (t->get_id () != LIFETIME)
7714 {
7715 // not necessarily an error
7716 return AST::LoopLabel::error ();
7717 }
7718 /* FIXME: check for named lifetime requirement here? or check in semantic
7719 * analysis phase? */
7720 AST::Lifetime label = parse_lifetime ();
7721
7722 if (!skip_token (COLON))
7723 {
7724 // skip somewhere?
7725 return AST::LoopLabel::error ();
7726 }
7727
7728 return AST::LoopLabel (std::move (label), t->get_locus ());
7729}
7730
7731/* Parses an if expression of any kind, including with else, else if, else if
7732 * let, and neither. Note that any outer attributes will be ignored because if
7733 * expressions don't support them. */
7734template <typename ManagedTokenSource>
7735std::unique_ptr<AST::IfExpr>
7736Parser<ManagedTokenSource>::parse_if_expr (AST::AttrVec outer_attrs,
7737 Location pratt_parsed_loc)
7738{
7739 // TODO: make having outer attributes an error?
7740 Location locus = pratt_parsed_loc;
7741 if (locus == Linemap::unknown_location ())
7742 {
7743 locus = lexer.peek_token ()->get_locus ();
7744 if (!skip_token (IF))
7745 {
7746 skip_after_end_block ();
7747 return nullptr;
7748 }
7749 }
7750
7751 // detect accidental if let
7752 if (lexer.peek_token ()->get_id () == LET)
7753 {
7754 Error error (lexer.peek_token ()->get_locus (),
7755 "if let expression probably exists, but is being parsed "
7756 "as an if expression. This may be a parser error");
7757 add_error (std::move (error));
7758
7759 // skip somewhere?
7760 return nullptr;
7761 }
7762
7763 /* parse required condition expr - HACK to prevent struct expr from being
7764 * parsed */
7765 ParseRestrictions no_struct_expr;
7766 no_struct_expr.can_be_struct_expr = false;
7767 std::unique_ptr<AST::Expr> condition = parse_expr ({}, no_struct_expr);
7768 if (condition == nullptr)
7769 {
7770 Error error (lexer.peek_token ()->get_locus (),
7771 "failed to parse condition expression in if expression");
7772 add_error (std::move (error));
7773
7774 // skip somewhere?
7775 return nullptr;
7776 }
7777
7778 // parse required block expr
7779 std::unique_ptr<AST::BlockExpr> if_body = parse_block_expr ();
7780 if (if_body == nullptr)
7781 {
7782 Error error (lexer.peek_token ()->get_locus (),
7783 "failed to parse if body block expression in if expression");
7784 add_error (std::move (error));
7785
7786 // skip somewhere?
7787 return nullptr;
7788 }
7789
7790 // branch to parse end or else (and then else, else if, or else if let)
7791 if (lexer.peek_token ()->get_id () != ELSE)
7792 {
7793 // single selection - end of if expression
7794 return std::unique_ptr<AST::IfExpr> (
7795 new AST::IfExpr (std::move (condition), std::move (if_body),
7796 std::move (outer_attrs), locus));
7797 }
7798 else
7799 {
7800 // double or multiple selection - branch on end, else if, or else if let
7801
7802 // skip "else"
7803 lexer.skip_token ();
7804
7805 // branch on whether next token is '{' or 'if'
7806 const_TokenPtr t = lexer.peek_token ();
7807 switch (t->get_id ())
7808 {
7809 case LEFT_CURLY: {
7810 // double selection - else
7811 // parse else block expr (required)
7812 std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr ();
7813 if (else_body == nullptr)
7814 {
7815 Error error (lexer.peek_token ()->get_locus (),
7816 "failed to parse else body block expression in "
7817 "if expression");
7818 add_error (std::move (error));
7819
7820 // skip somewhere?
7821 return nullptr;
7822 }
7823
7824 return std::unique_ptr<AST::IfExprConseqElse> (
7825 new AST::IfExprConseqElse (std::move (condition),
7826 std::move (if_body),
7827 std::move (else_body),
7828 std::move (outer_attrs), locus));
7829 }
7830 case IF: {
7831 // multiple selection - else if or else if let
7832 // branch on whether next token is 'let' or not
7833 if (lexer.peek_token (1)->get_id () == LET)
7834 {
7835 // parse if let expr (required)
7836 std::unique_ptr<AST::IfLetExpr> if_let_expr
7837 = parse_if_let_expr ();
7838 if (if_let_expr == nullptr)
7839 {
7840 Error error (lexer.peek_token ()->get_locus (),
7841 "failed to parse (else) if let expression "
7842 "after if expression");
7843 add_error (std::move (error));
7844
7845 // skip somewhere?
7846 return nullptr;
7847 }
7848
7849 return std::unique_ptr<AST::IfExprConseqIfLet> (
7850 new AST::IfExprConseqIfLet (std::move (condition),
7851 std::move (if_body),
7852 std::move (if_let_expr),
7853 std::move (outer_attrs), locus));
7854 }
7855 else
7856 {
7857 // parse if expr (required)
7858 std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr ();
7859 if (if_expr == nullptr)
7860 {
7861 Error error (lexer.peek_token ()->get_locus (),
7862 "failed to parse (else) if expression after "
7863 "if expression");
7864 add_error (std::move (error));
7865
7866 // skip somewhere?
7867 return nullptr;
7868 }
7869
7870 return std::unique_ptr<AST::IfExprConseqIf> (
7871 new AST::IfExprConseqIf (std::move (condition),
7872 std::move (if_body),
7873 std::move (if_expr),
7874 std::move (outer_attrs), locus));
7875 }
7876 }
7877 default:
7878 // error - invalid token
7879 add_error (Error (t->get_locus (),
7880 "unexpected token %qs after else in if expression",
7881 t->get_token_description ()));
7882
7883 // skip somewhere?
7884 return nullptr;
7885 }
7886 }
7887}
7888
7889/* Parses an if let expression of any kind, including with else, else if, else
7890 * if let, and none. Note that any outer attributes will be ignored as if let
7891 * expressions don't support them. */
7892template <typename ManagedTokenSource>
7893std::unique_ptr<AST::IfLetExpr>
7894Parser<ManagedTokenSource>::parse_if_let_expr (AST::AttrVec outer_attrs,
7895 Location pratt_parsed_loc)
7896{
7897 // TODO: make having outer attributes an error?
7898 Location locus = pratt_parsed_loc;
7899 if (locus == Linemap::unknown_location ())
7900 {
7901 locus = lexer.peek_token ()->get_locus ();
7902 if (!skip_token (IF))
7903 {
7904 skip_after_end_block ();
7905 return nullptr;
7906 }
7907 }
7908
7909 // detect accidental if expr parsed as if let expr
7910 if (lexer.peek_token ()->get_id () != LET)
7911 {
7912 Error error (lexer.peek_token ()->get_locus (),
7913 "if expression probably exists, but is being parsed as an "
7914 "if let expression. This may be a parser error");
7915 add_error (std::move (error));
7916
7917 // skip somewhere?
7918 return nullptr;
7919 }
7920 lexer.skip_token ();
7921
7922 // parse match arm patterns (which are required)
7923 std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns
7924 = parse_match_arm_patterns (EQUAL);
7925 if (match_arm_patterns.empty ())
7926 {
7927 Error error (
7928 lexer.peek_token ()->get_locus (),
7929 "failed to parse any match arm patterns in if let expression");
7930 add_error (std::move (error));
7931
7932 // skip somewhere?
7933 return nullptr;
7934 }
7935
7936 if (!skip_token (EQUAL))
7937 {
7938 // skip somewhere?
7939 return nullptr;
7940 }
7941
7942 // parse expression (required) - HACK to prevent struct expr being parsed
7943 ParseRestrictions no_struct_expr;
7944 no_struct_expr.can_be_struct_expr = false;
7945 std::unique_ptr<AST::Expr> scrutinee_expr = parse_expr ({}, no_struct_expr);
7946 if (scrutinee_expr == nullptr)
7947 {
7948 Error error (lexer.peek_token ()->get_locus (),
7949 "failed to parse scrutinee expression in if let expression");
7950 add_error (std::move (error));
7951
7952 // skip somewhere?
7953 return nullptr;
7954 }
7955 /* TODO: check for expression not being a struct expression or lazy boolean
7956 * expression here? or actually probably in semantic analysis. */
7957
7958 // parse block expression (required)
7959 std::unique_ptr<AST::BlockExpr> if_let_body = parse_block_expr ();
7960 if (if_let_body == nullptr)
7961 {
7962 Error error (
7963 lexer.peek_token ()->get_locus (),
7964 "failed to parse if let body block expression in if let expression");
7965 add_error (std::move (error));
7966
7967 // skip somewhere?
7968 return nullptr;
7969 }
7970
7971 // branch to parse end or else (and then else, else if, or else if let)
7972 if (lexer.peek_token ()->get_id () != ELSE)
7973 {
7974 // single selection - end of if let expression
7975 return std::unique_ptr<AST::IfLetExpr> (
7976 new AST::IfLetExpr (std::move (match_arm_patterns),
7977 std::move (scrutinee_expr), std::move (if_let_body),
7978 std::move (outer_attrs), locus));
7979 }
7980 else
7981 {
7982 // double or multiple selection - branch on end, else if, or else if let
7983
7984 // skip "else"
7985 lexer.skip_token ();
7986
7987 // branch on whether next token is '{' or 'if'
7988 const_TokenPtr t = lexer.peek_token ();
7989 switch (t->get_id ())
7990 {
7991 case LEFT_CURLY: {
7992 // double selection - else
7993 // parse else block expr (required)
7994 std::unique_ptr<AST::BlockExpr> else_body = parse_block_expr ();
7995 if (else_body == nullptr)
7996 {
7997 Error error (lexer.peek_token ()->get_locus (),
7998 "failed to parse else body block expression in "
7999 "if let expression");
8000 add_error (std::move (error));
8001
8002 // skip somewhere?
8003 return nullptr;
8004 }
8005
8006 return std::unique_ptr<AST::IfLetExprConseqElse> (
8007 new AST::IfLetExprConseqElse (std::move (match_arm_patterns),
8008 std::move (scrutinee_expr),
8009 std::move (if_let_body),
8010 std::move (else_body),
8011 std::move (outer_attrs), locus));
8012 }
8013 case IF: {
8014 // multiple selection - else if or else if let
8015 // branch on whether next token is 'let' or not
8016 if (lexer.peek_token (1)->get_id () == LET)
8017 {
8018 // parse if let expr (required)
8019 std::unique_ptr<AST::IfLetExpr> if_let_expr
8020 = parse_if_let_expr ();
8021 if (if_let_expr == nullptr)
8022 {
8023 Error error (lexer.peek_token ()->get_locus (),
8024 "failed to parse (else) if let expression "
8025 "after if let expression");
8026 add_error (std::move (error));
8027
8028 // skip somewhere?
8029 return nullptr;
8030 }
8031
8032 return std::unique_ptr<AST::IfLetExprConseqIfLet> (
8033 new AST::IfLetExprConseqIfLet (
8034 std::move (match_arm_patterns), std::move (scrutinee_expr),
8035 std::move (if_let_body), std::move (if_let_expr),
8036 std::move (outer_attrs), locus));
8037 }
8038 else
8039 {
8040 // parse if expr (required)
8041 std::unique_ptr<AST::IfExpr> if_expr = parse_if_expr ();
8042 if (if_expr == nullptr)
8043 {
8044 Error error (lexer.peek_token ()->get_locus (),
8045 "failed to parse (else) if expression after "
8046 "if let expression");
8047 add_error (std::move (error));
8048
8049 // skip somewhere?
8050 return nullptr;
8051 }
8052
8053 return std::unique_ptr<AST::IfLetExprConseqIf> (
8054 new AST::IfLetExprConseqIf (std::move (match_arm_patterns),
8055 std::move (scrutinee_expr),
8056 std::move (if_let_body),
8057 std::move (if_expr),
8058 std::move (outer_attrs), locus));
8059 }
8060 }
8061 default:
8062 // error - invalid token
8063 add_error (
8064 Error (t->get_locus (),
8065 "unexpected token %qs after else in if let expression",
8066 t->get_token_description ()));
8067
8068 // skip somewhere?
8069 return nullptr;
8070 }
8071 }
8072}
8073
8074/* TODO: possibly decide on different method of handling label (i.e. not
8075 * parameter) */
8076
8077/* Parses a "loop" infinite loop expression. Label is not parsed and should be
8078 * parsed via parse_labelled_loop_expr, which would call this. */
8079template <typename ManagedTokenSource>
8080std::unique_ptr<AST::LoopExpr>
8081Parser<ManagedTokenSource>::parse_loop_expr (AST::AttrVec outer_attrs,
8082 AST::LoopLabel label,
8083 Location pratt_parsed_loc)
8084{
8085 Location locus = pratt_parsed_loc;
8086 if (locus == Linemap::unknown_location ())
8087 {
8088 if (label.is_error ())
8089 locus = lexer.peek_token ()->get_locus ();
8090 else
8091 locus = label.get_locus ();
8092
8093 if (!skip_token (LOOP))
8094 {
8095 skip_after_end_block ();
8096 return nullptr;
8097 }
8098 }
8099 else
8100 {
8101 if (!label.is_error ())
8102 locus = label.get_locus ();
8103 }
8104
8105 // parse loop body, which is required
8106 std::unique_ptr<AST::BlockExpr> loop_body = parse_block_expr ();
8107 if (loop_body == nullptr)
8108 {
8109 Error error (lexer.peek_token ()->get_locus (),
8110 "could not parse loop body in (infinite) loop expression");
8111 add_error (std::move (error));
8112
8113 return nullptr;
8114 }
8115
8116 return std::unique_ptr<AST::LoopExpr> (
8117 new AST::LoopExpr (std::move (loop_body), locus, std::move (label),
8118 std::move (outer_attrs)));
8119}
8120
8121/* Parses a "while" loop expression. Label is not parsed and should be parsed
8122 * via parse_labelled_loop_expr, which would call this. */
8123template <typename ManagedTokenSource>
8124std::unique_ptr<AST::WhileLoopExpr>
8125Parser<ManagedTokenSource>::parse_while_loop_expr (AST::AttrVec outer_attrs,
8126 AST::LoopLabel label,
8127 Location pratt_parsed_loc)
8128{
8129 Location locus = pratt_parsed_loc;
8130 if (locus == Linemap::unknown_location ())
8131 {
8132 if (label.is_error ())
8133 locus = lexer.peek_token ()->get_locus ();
8134 else
8135 locus = label.get_locus ();
8136
8137 if (!skip_token (WHILE))
8138 {
8139 skip_after_end_block ();
8140 return nullptr;
8141 }
8142 }
8143 else
8144 {
8145 if (!label.is_error ())
8146 locus = label.get_locus ();
8147 }
8148
8149 // ensure it isn't a while let loop
8150 if (lexer.peek_token ()->get_id () == LET)
8151 {
8152 Error error (lexer.peek_token ()->get_locus (),
8153 "appears to be while let loop but is being parsed by "
8154 "while loop - this may be a compiler issue");
8155 add_error (std::move (error));
8156
8157 // skip somewhere?
8158 return nullptr;
8159 }
8160
8161 // parse loop predicate (required) with HACK to prevent struct expr parsing
8162 ParseRestrictions no_struct_expr;
8163 no_struct_expr.can_be_struct_expr = false;
8164 std::unique_ptr<AST::Expr> predicate = parse_expr ({}, no_struct_expr);
8165 if (predicate == nullptr)
8166 {
8167 Error error (lexer.peek_token ()->get_locus (),
8168 "failed to parse predicate expression in while loop");
8169 add_error (std::move (error));
8170
8171 // skip somewhere?
8172 return nullptr;
8173 }
8174 /* TODO: check that it isn't struct expression here? actually, probably in
8175 * semantic analysis */
8176
8177 // parse loop body (required)
8178 std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
8179 if (body == nullptr)
8180 {
8181 Error error (lexer.peek_token ()->get_locus (),
8182 "failed to parse loop body block expression in while loop");
8183 add_error (std::move (error));
8184
8185 // skip somewhere
8186 return nullptr;
8187 }
8188
8189 return std::unique_ptr<AST::WhileLoopExpr> (
8190 new AST::WhileLoopExpr (std::move (predicate), std::move (body), locus,
8191 std::move (label), std::move (outer_attrs)));
8192}
8193
8194/* Parses a "while let" loop expression. Label is not parsed and should be
8195 * parsed via parse_labelled_loop_expr, which would call this. */
8196template <typename ManagedTokenSource>
8197std::unique_ptr<AST::WhileLetLoopExpr>
8198Parser<ManagedTokenSource>::parse_while_let_loop_expr (AST::AttrVec outer_attrs,
8199 AST::LoopLabel label)
8200{
8201 Location locus = Linemap::unknown_location ();
8202 if (label.is_error ())
8203 locus = lexer.peek_token ()->get_locus ();
8204 else
8205 locus = label.get_locus ();
8206 skip_token (WHILE);
8207
8208 /* check for possible accidental recognition of a while loop as a while let
8209 * loop */
8210 if (lexer.peek_token ()->get_id () != LET)
8211 {
8212 Error error (lexer.peek_token ()->get_locus (),
8213 "appears to be a while loop but is being parsed by "
8214 "while let loop - this may be a compiler issue");
8215 add_error (std::move (error));
8216
8217 // skip somewhere
8218 return nullptr;
8219 }
8220 // as this token is definitely let now, save the computation of comparison
8221 lexer.skip_token ();
8222
8223 // parse predicate patterns
8224 std::vector<std::unique_ptr<AST::Pattern>> predicate_patterns
8225 = parse_match_arm_patterns (EQUAL);
8226 // TODO: have to ensure that there is at least 1 pattern?
8227
8228 if (!skip_token (EQUAL))
8229 {
8230 // skip somewhere?
8231 return nullptr;
8232 }
8233
8234 /* parse predicate expression, which is required (and HACK to prevent struct
8235 * expr) */
8236 ParseRestrictions no_struct_expr;
8237 no_struct_expr.can_be_struct_expr = false;
8238 std::unique_ptr<AST::Expr> predicate_expr = parse_expr ({}, no_struct_expr);
8239 if (predicate_expr == nullptr)
8240 {
8241 Error error (lexer.peek_token ()->get_locus (),
8242 "failed to parse predicate expression in while let loop");
8243 add_error (std::move (error));
8244
8245 // skip somewhere?
8246 return nullptr;
8247 }
8248 /* TODO: ensure that struct expression is not parsed? Actually, probably in
8249 * semantic analysis. */
8250
8251 // parse loop body, which is required
8252 std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
8253 if (body == nullptr)
8254 {
8255 Error error (lexer.peek_token ()->get_locus (),
8256 "failed to parse block expr (loop body) of while let loop");
8257 add_error (std::move (error));
8258
8259 // skip somewhere?
8260 return nullptr;
8261 }
8262
8263 return std::unique_ptr<AST::WhileLetLoopExpr> (new AST::WhileLetLoopExpr (
8264 std::move (predicate_patterns), std::move (predicate_expr),
8265 std::move (body), locus, std::move (label), std::move (outer_attrs)));
8266}
8267
8268/* Parses a "for" iterative loop. Label is not parsed and should be parsed via
8269 * parse_labelled_loop_expr, which would call this. */
8270template <typename ManagedTokenSource>
8271std::unique_ptr<AST::ForLoopExpr>
8272Parser<ManagedTokenSource>::parse_for_loop_expr (AST::AttrVec outer_attrs,
8273 AST::LoopLabel label)
8274{
8275 Location locus = Linemap::unknown_location ();
8276 if (label.is_error ())
8277 locus = lexer.peek_token ()->get_locus ();
8278 else
8279 locus = label.get_locus ();
8280 skip_token (FOR);
8281
8282 // parse pattern, which is required
8283 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
8284 if (pattern == nullptr)
8285 {
8286 Error error (lexer.peek_token ()->get_locus (),
8287 "failed to parse iterator pattern in for loop");
8288 add_error (std::move (error));
8289
8290 // skip somewhere?
8291 return nullptr;
8292 }
8293
8294 if (!skip_token (IN))
8295 {
8296 // skip somewhere?
8297 return nullptr;
8298 }
8299
8300 /* parse iterator expression, which is required - also HACK to prevent
8301 * struct expr */
8302 ParseRestrictions no_struct_expr;
8303 no_struct_expr.can_be_struct_expr = false;
8304 std::unique_ptr<AST::Expr> expr = parse_expr ({}, no_struct_expr);
8305 if (expr == nullptr)
8306 {
8307 Error error (lexer.peek_token ()->get_locus (),
8308 "failed to parse iterator expression in for loop");
8309 add_error (std::move (error));
8310
8311 // skip somewhere?
8312 return nullptr;
8313 }
8314 // TODO: check to ensure this isn't struct expr? Or in semantic analysis.
8315
8316 // parse loop body, which is required
8317 std::unique_ptr<AST::BlockExpr> body = parse_block_expr ();
8318 if (body == nullptr)
8319 {
8320 Error error (lexer.peek_token ()->get_locus (),
8321 "failed to parse loop body block expression in for loop");
8322 add_error (std::move (error));
8323
8324 // skip somewhere?
8325 return nullptr;
8326 }
8327
8328 return std::unique_ptr<AST::ForLoopExpr> (
8329 new AST::ForLoopExpr (std::move (pattern), std::move (expr),
8330 std::move (body), locus, std::move (label),
8331 std::move (outer_attrs)));
8332}
8333
8334// Parses a loop expression with label (any kind of loop - disambiguates).
8335template <typename ManagedTokenSource>
8336std::unique_ptr<AST::BaseLoopExpr>
8337Parser<ManagedTokenSource>::parse_labelled_loop_expr (AST::AttrVec outer_attrs)
8338{
8339 /* TODO: decide whether it should not work if there is no label, or parse it
8340 * with no label at the moment, I will make it not work with no label
8341 * because that's the implication. */
8342
8343 if (lexer.peek_token ()->get_id () != LIFETIME)
8344 {
8345 Error error (lexer.peek_token ()->get_locus (),
8346 "expected lifetime in labelled loop expr (to parse loop "
8347 "label) - found %qs",
8348 lexer.peek_token ()->get_token_description ());
8349 add_error (std::move (error));
8350
8351 // skip?
8352 return nullptr;
8353 }
8354
8355 // parse loop label (required)
8356 AST::LoopLabel label = parse_loop_label ();
8357 if (label.is_error ())
8358 {
8359 Error error (lexer.peek_token ()->get_locus (),
8360 "failed to parse loop label in labelled loop expr");
8361 add_error (std::move (error));
8362
8363 // skip?
8364 return nullptr;
8365 }
8366
8367 // branch on next token
8368 const_TokenPtr t = lexer.peek_token ();
8369 switch (t->get_id ())
8370 {
8371 case LOOP:
8372 return parse_loop_expr (std::move (outer_attrs), std::move (label));
8373 case FOR:
8374 return parse_for_loop_expr (std::move (outer_attrs), std::move (label));
8375 case WHILE:
8376 // further disambiguate into while vs while let
8377 if (lexer.peek_token (1)->get_id () == LET)
8378 {
8379 return parse_while_let_loop_expr (std::move (outer_attrs),
8380 std::move (label));
8381 }
8382 else
8383 {
8384 return parse_while_loop_expr (std::move (outer_attrs),
8385 std::move (label));
8386 }
8387 default:
8388 // error
8389 add_error (Error (t->get_locus (),
8390 "unexpected token %qs when parsing labelled loop",
8391 t->get_token_description ()));
8392
8393 // skip?
8394 return nullptr;
8395 }
8396}
8397
8398// Parses a match expression.
8399template <typename ManagedTokenSource>
8400std::unique_ptr<AST::MatchExpr>
8401Parser<ManagedTokenSource>::parse_match_expr (AST::AttrVec outer_attrs,
8402 Location pratt_parsed_loc)
8403{
8404 Location locus = pratt_parsed_loc;
8405 if (locus == Linemap::unknown_location ())
8406 {
8407 locus = lexer.peek_token ()->get_locus ();
8408 skip_token (MATCH_TOK);
8409 }
8410
8411 /* parse scrutinee expression, which is required (and HACK to prevent struct
8412 * expr) */
8413 ParseRestrictions no_struct_expr;
8414 no_struct_expr.can_be_struct_expr = false;
8415 std::unique_ptr<AST::Expr> scrutinee = parse_expr ({}, no_struct_expr);
8416 if (scrutinee == nullptr)
8417 {
8418 Error error (lexer.peek_token ()->get_locus (),
8419 "failed to parse scrutinee expression in match expression");
8420 add_error (std::move (error));
8421
8422 // skip somewhere?
8423 return nullptr;
8424 }
8425 /* TODO: check for scrutinee expr not being struct expr? or do so in
8426 * semantic analysis */
8427
8428 if (!skip_token (LEFT_CURLY))
8429 {
8430 // skip somewhere?
8431 return nullptr;
8432 }
8433
8434 // parse inner attributes (if they exist)
8435 AST::AttrVec inner_attrs = parse_inner_attributes ();
8436
8437 // parse match arms (if they exist)
8438 // std::vector<std::unique_ptr<AST::MatchCase> > match_arms;
8439 std::vector<AST::MatchCase> match_arms;
8440
8441 // parse match cases
8442 while (lexer.peek_token ()->get_id () != RIGHT_CURLY)
8443 {
8444 // parse match arm itself, which is required
8445 AST::MatchArm arm = parse_match_arm ();
8446 if (arm.is_error ())
8447 {
8448 // TODO is this worth throwing everything away?
8449 Error error (lexer.peek_token ()->get_locus (),
8450 "failed to parse match arm in match arms");
8451 add_error (std::move (error));
8452
8453 return nullptr;
8454 }
8455
8456 if (!skip_token (MATCH_ARROW))
8457 {
8458 // skip after somewhere?
8459 // TODO is returning here a good idea? or is break better?
8460 return nullptr;
8461 }
8462
8463 ParseRestrictions restrictions;
8464 restrictions.expr_can_be_stmt = true;
8465 restrictions.consume_semi = false;
8466
8467 std::unique_ptr<AST::ExprStmt> expr = parse_expr_stmt ({}, restrictions);
8468 if (expr == nullptr)
8469 {
8470 Error error (lexer.peek_token ()->get_locus (),
8471 "failed to parse expr in match arm in match expr");
8472 add_error (std::move (error));
8473
8474 // skip somewhere?
8475 return nullptr;
8476 }
8477 bool is_expr_without_block
8478 = expr->get_type () == AST::ExprStmt::ExprStmtType::WITHOUT_BLOCK;
8479
8480 // construct match case expr and add to cases
8481 switch (expr->get_type ())
8482 {
8483 case AST::ExprStmt::ExprStmtType::WITH_BLOCK: {
8484 AST::ExprStmtWithBlock *cast
8485 = static_cast<AST::ExprStmtWithBlock *> (expr.get ());
8486 std::unique_ptr<AST::Expr> e = cast->get_expr ()->clone_expr ();
8487 match_arms.push_back (
8488 AST::MatchCase (std::move (arm), std::move (e)));
8489 }
8490 break;
8491
8492 case AST::ExprStmt::ExprStmtType::WITHOUT_BLOCK: {
8493 AST::ExprStmtWithoutBlock *cast
8494 = static_cast<AST::ExprStmtWithoutBlock *> (expr.get ());
8495 std::unique_ptr<AST::Expr> e = cast->get_expr ()->clone_expr ();
8496 match_arms.push_back (
8497 AST::MatchCase (std::move (arm), std::move (e)));
8498 }
8499 break;
8500 }
8501
8502 // handle comma presence
8503 if (lexer.peek_token ()->get_id () != COMMA)
8504 {
8505 if (!is_expr_without_block)
8506 {
8507 // allowed even if not final case
8508 continue;
8509 }
8510 else if (is_expr_without_block
8511 && lexer.peek_token ()->get_id () != RIGHT_CURLY)
8512 {
8513 // not allowed if not final case
8514 Error error (lexer.peek_token ()->get_locus (),
8515 "exprwithoutblock requires comma after match case "
8516 "expression in match arm (if not final case)");
8517 add_error (std::move (error));
8518
8519 return nullptr;
8520 }
8521 else
8522 {
8523 // otherwise, must be final case, so fine
8524 break;
8525 }
8526 }
8527 lexer.skip_token ();
8528 }
8529
8530 if (!skip_token (RIGHT_CURLY))
8531 {
8532 // skip somewhere?
8533 return nullptr;
8534 }
8535
8536 match_arms.shrink_to_fit ();
8537
8538 return std::unique_ptr<AST::MatchExpr> (
8539 new AST::MatchExpr (std::move (scrutinee), std::move (match_arms),
8540 std::move (inner_attrs), std::move (outer_attrs),
8541 locus));
8542}
8543
8544// Parses the "pattern" part of the match arm (the 'case x:' equivalent).
8545template <typename ManagedTokenSource>
8546AST::MatchArm
8547Parser<ManagedTokenSource>::parse_match_arm ()
8548{
8549 // parse optional outer attributes
8550 AST::AttrVec outer_attrs = parse_outer_attributes ();
8551
8552 // DEBUG
8553 rust_debug ("about to start parsing match arm patterns");
8554
8555 // break early if find right curly
8556 if (lexer.peek_token ()->get_id () == RIGHT_CURLY)
8557 {
8558 // not an error
8559 return AST::MatchArm::create_error ();
8560 }
8561
8562 // parse match arm patterns - at least 1 is required
8563 std::vector<std::unique_ptr<AST::Pattern>> match_arm_patterns
8564 = parse_match_arm_patterns (RIGHT_CURLY);
8565 if (match_arm_patterns.empty ())
8566 {
8567 Error error (lexer.peek_token ()->get_locus (),
8568 "failed to parse any patterns in match arm");
8569 add_error (std::move (error));
8570
8571 // skip somewhere?
8572 return AST::MatchArm::create_error ();
8573 }
8574
8575 // DEBUG
8576 rust_debug ("successfully parsed match arm patterns");
8577
8578 // parse match arm guard expr if it exists
8579 std::unique_ptr<AST::Expr> guard_expr = nullptr;
8580 if (lexer.peek_token ()->get_id () == IF)
8581 {
8582 lexer.skip_token ();
8583
8584 guard_expr = parse_expr ();
8585 if (guard_expr == nullptr)
8586 {
8587 Error error (lexer.peek_token ()->get_locus (),
8588 "failed to parse guard expression in match arm");
8589 add_error (std::move (error));
8590
8591 // skip somewhere?
8592 return AST::MatchArm::create_error ();
8593 }
8594 }
8595
8596 // DEBUG
8597 rust_debug ("successfully parsed match arm");
8598
8599 return AST::MatchArm (std::move (match_arm_patterns),
8600 lexer.peek_token ()->get_locus (),
8601 std::move (guard_expr), std::move (outer_attrs));
8602}
8603
8604/* Parses the patterns used in a match arm. End token id is the id of the
8605 * token that would exist after the patterns are done (e.g. '}' for match
8606 * expr, '=' for if let and while let). */
8607template <typename ManagedTokenSource>
8608std::vector<std::unique_ptr<AST::Pattern>>
8609Parser<ManagedTokenSource>::parse_match_arm_patterns (TokenId end_token_id)
8610{
8611 // skip optional leading '|'
8612 if (lexer.peek_token ()->get_id () == PIPE)
8613 lexer.skip_token ();
8614 /* TODO: do I even need to store the result of this? can't be used.
8615 * If semantically different, I need a wrapped "match arm patterns" object
8616 * for this. */
8617
8618 std::vector<std::unique_ptr<AST::Pattern>> patterns;
8619
8620 // quick break out if end_token_id
8621 if (lexer.peek_token ()->get_id () == end_token_id)
8622 return patterns;
8623
8624 // parse required pattern - if doesn't exist, return empty
8625 std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
8626 if (initial_pattern == nullptr)
8627 {
8628 // FIXME: should this be an error?
8629 return patterns;
8630 }
8631 patterns.push_back (std::move (initial_pattern));
8632
8633 // DEBUG
8634 rust_debug ("successfully parsed initial match arm pattern");
8635
8636 // parse new patterns as long as next char is '|'
8637 const_TokenPtr t = lexer.peek_token ();
8638 while (t->get_id () == PIPE)
8639 {
8640 // skip pipe token
8641 lexer.skip_token ();
8642
8643 // break if hit end token id
8644 if (lexer.peek_token ()->get_id () == end_token_id)
8645 break;
8646
8647 // parse pattern
8648 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
8649 if (pattern == nullptr)
8650 {
8651 // this is an error
8652 Error error (lexer.peek_token ()->get_locus (),
8653 "failed to parse pattern in match arm patterns");
8654 add_error (std::move (error));
8655
8656 // skip somewhere?
8657 return {};
8658 }
8659
8660 patterns.push_back (std::move (pattern));
8661
8662 t = lexer.peek_token ();
8663 }
8664
8665 patterns.shrink_to_fit ();
8666
8667 return patterns;
8668}
8669
8670// Parses an async block expression.
8671template <typename ManagedTokenSource>
8672std::unique_ptr<AST::AsyncBlockExpr>
8673Parser<ManagedTokenSource>::parse_async_block_expr (AST::AttrVec outer_attrs)
8674{
8675 Location locus = lexer.peek_token ()->get_locus ();
8676 skip_token (ASYNC);
8677
8678 // detect optional move token
8679 bool has_move = false;
8680 if (lexer.peek_token ()->get_id () == MOVE)
8681 {
8682 lexer.skip_token ();
8683 has_move = true;
8684 }
8685
8686 // parse block expression (required)
8687 std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
8688 if (block_expr == nullptr)
8689 {
8690 Error error (
8691 lexer.peek_token ()->get_locus (),
8692 "failed to parse block expression of async block expression");
8693 add_error (std::move (error));
8694
8695 // skip somewhere?
8696 return nullptr;
8697 }
8698
8699 return std::unique_ptr<AST::AsyncBlockExpr> (
8700 new AST::AsyncBlockExpr (std::move (block_expr), has_move,
8701 std::move (outer_attrs), locus));
8702}
8703
8704// Parses an unsafe block expression.
8705template <typename ManagedTokenSource>
8706std::unique_ptr<AST::UnsafeBlockExpr>
8707Parser<ManagedTokenSource>::parse_unsafe_block_expr (AST::AttrVec outer_attrs,
8708 Location pratt_parsed_loc)
8709{
8710 Location locus = pratt_parsed_loc;
8711 if (locus == Linemap::unknown_location ())
8712 {
8713 locus = lexer.peek_token ()->get_locus ();
8714 skip_token (UNSAFE);
8715 }
8716
8717 // parse block expression (required)
8718 std::unique_ptr<AST::BlockExpr> block_expr = parse_block_expr ();
8719 if (block_expr == nullptr)
8720 {
8721 Error error (
8722 lexer.peek_token ()->get_locus (),
8723 "failed to parse block expression of unsafe block expression");
8724 add_error (std::move (error));
8725
8726 // skip somewhere?
8727 return nullptr;
8728 }
8729
8730 return std::unique_ptr<AST::UnsafeBlockExpr> (
8731 new AST::UnsafeBlockExpr (std::move (block_expr), std::move (outer_attrs),
8732 locus));
8733}
8734
8735// Parses an array definition expression.
8736template <typename ManagedTokenSource>
8737std::unique_ptr<AST::ArrayExpr>
8738Parser<ManagedTokenSource>::parse_array_expr (AST::AttrVec outer_attrs,
8739 Location pratt_parsed_loc)
8740{
8741 Location locus = pratt_parsed_loc;
8742 if (locus == Linemap::unknown_location ())
8743 {
8744 locus = lexer.peek_token ()->get_locus ();
8745 skip_token (LEFT_SQUARE);
8746 }
8747
8748 // parse optional inner attributes
8749 AST::AttrVec inner_attrs = parse_inner_attributes ();
8750
8751 // parse the "array elements" section, which is optional
8752 if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
8753 {
8754 // no array elements
8755 lexer.skip_token ();
8756
8757 std::vector<std::unique_ptr<AST::Expr>> exprs;
8758 auto array_elems
8759 = Rust::make_unique<AST::ArrayElemsValues> (std::move (exprs), locus);
8760 return Rust::make_unique<AST::ArrayExpr> (std::move (array_elems),
8761 std::move (inner_attrs),
8762 std::move (outer_attrs), locus);
8763 }
8764 else
8765 {
8766 // should have array elements
8767 // parse initial expression, which is required for either
8768 std::unique_ptr<AST::Expr> initial_expr = parse_expr ();
8769 if (initial_expr == nullptr)
8770 {
8771 Error error (lexer.peek_token ()->get_locus (),
8772 "could not parse expression in array expression "
8773 "(even though arrayelems seems to be present)");
8774 add_error (std::move (error));
8775
8776 // skip somewhere?
8777 return nullptr;
8778 }
8779
8780 if (lexer.peek_token ()->get_id () == SEMICOLON)
8781 {
8782 // copy array elems
8783 lexer.skip_token ();
8784
8785 // parse copy amount expression (required)
8786 std::unique_ptr<AST::Expr> copy_amount = parse_expr ();
8787 if (copy_amount == nullptr)
8788 {
8789 Error error (lexer.peek_token ()->get_locus (),
8790 "could not parse copy amount expression in array "
8791 "expression (arrayelems)");
8792 add_error (std::move (error));
8793
8794 // skip somewhere?
8795 return nullptr;
8796 }
8797
8798 skip_token (RIGHT_SQUARE);
8799
8800 std::unique_ptr<AST::ArrayElemsCopied> copied_array_elems (
8801 new AST::ArrayElemsCopied (std::move (initial_expr),
8802 std::move (copy_amount), locus));
8803 return std::unique_ptr<AST::ArrayExpr> (
8804 new AST::ArrayExpr (std::move (copied_array_elems),
8805 std::move (inner_attrs),
8806 std::move (outer_attrs), locus));
8807 }
8808 else if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
8809 {
8810 // single-element array expression
8811 std::vector<std::unique_ptr<AST::Expr>> exprs;
8812 exprs.reserve (1);
8813 exprs.push_back (std::move (initial_expr));
8814 exprs.shrink_to_fit ();
8815
8816 skip_token (RIGHT_SQUARE);
8817
8818 std::unique_ptr<AST::ArrayElemsValues> array_elems (
8819 new AST::ArrayElemsValues (std::move (exprs), locus));
8820 return std::unique_ptr<AST::ArrayExpr> (
8821 new AST::ArrayExpr (std::move (array_elems),
8822 std::move (inner_attrs),
8823 std::move (outer_attrs), locus));
8824 }
8825 else if (lexer.peek_token ()->get_id () == COMMA)
8826 {
8827 // multi-element array expression (or trailing comma)
8828 std::vector<std::unique_ptr<AST::Expr>> exprs;
8829 exprs.push_back (std::move (initial_expr));
8830
8831 const_TokenPtr t = lexer.peek_token ();
8832 while (t->get_id () == COMMA)
8833 {
8834 lexer.skip_token ();
8835
8836 // quick break if right square bracket
8837 if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
8838 break;
8839
8840 // parse expression (required)
8841 std::unique_ptr<AST::Expr> expr = parse_expr ();
8842 if (expr == nullptr)
8843 {
8844 Error error (lexer.peek_token ()->get_locus (),
8845 "failed to parse element in array expression");
8846 add_error (std::move (error));
8847
8848 // skip somewhere?
8849 return nullptr;
8850 }
8851 exprs.push_back (std::move (expr));
8852
8853 t = lexer.peek_token ();
8854 }
8855
8856 skip_token (RIGHT_SQUARE);
8857
8858 exprs.shrink_to_fit ();
8859
8860 std::unique_ptr<AST::ArrayElemsValues> array_elems (
8861 new AST::ArrayElemsValues (std::move (exprs), locus));
8862 return std::unique_ptr<AST::ArrayExpr> (
8863 new AST::ArrayExpr (std::move (array_elems),
8864 std::move (inner_attrs),
8865 std::move (outer_attrs), locus));
8866 }
8867 else
8868 {
8869 // error
8870 Error error (lexer.peek_token ()->get_locus (),
8871 "unexpected token %qs in array expression (arrayelems)",
8872 lexer.peek_token ()->get_token_description ());
8873 add_error (std::move (error));
8874
8875 // skip somewhere?
8876 return nullptr;
8877 }
8878 }
8879}
8880
8881// Parses a single parameter used in a closure definition.
8882template <typename ManagedTokenSource>
8883AST::ClosureParam
8884Parser<ManagedTokenSource>::parse_closure_param ()
8885{
8886 AST::AttrVec outer_attrs = parse_outer_attributes ();
8887
8888 // parse pattern (which is required)
8889 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
8890 if (pattern == nullptr)
8891 {
8892 // not necessarily an error
8893 return AST::ClosureParam::create_error ();
8894 }
8895
8896 // parse optional type of param
8897 std::unique_ptr<AST::Type> type = nullptr;
8898 if (lexer.peek_token ()->get_id () == COLON)
8899 {
8900 lexer.skip_token ();
8901
8902 // parse type, which is now required
8903 type = parse_type ();
8904 if (type == nullptr)
8905 {
8906 Error error (lexer.peek_token ()->get_locus (),
8907 "failed to parse type in closure parameter");
8908 add_error (std::move (error));
8909
8910 // skip somewhere?
8911 return AST::ClosureParam::create_error ();
8912 }
8913 }
8914
95dc1147
JJ
8915 Location loc = pattern->get_locus ();
8916 return AST::ClosureParam (std::move (pattern), loc, std::move (type),
8917 std::move (outer_attrs));
32c8fb0e
JP
8918}
8919
8920// Parses a grouped or tuple expression (disambiguates).
8921template <typename ManagedTokenSource>
8922std::unique_ptr<AST::ExprWithoutBlock>
8923Parser<ManagedTokenSource>::parse_grouped_or_tuple_expr (
8924 AST::AttrVec outer_attrs, Location pratt_parsed_loc)
8925{
8926 // adjustment to allow Pratt parsing to reuse function without copy-paste
8927 Location locus = pratt_parsed_loc;
8928 if (locus == Linemap::unknown_location ())
8929 {
8930 locus = lexer.peek_token ()->get_locus ();
8931 skip_token (LEFT_PAREN);
8932 }
8933
8934 // parse optional inner attributes
8935 AST::AttrVec inner_attrs = parse_inner_attributes ();
8936
8937 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
8938 {
8939 // must be empty tuple
8940 lexer.skip_token ();
8941
8942 // create tuple with empty tuple elems
8943 return std::unique_ptr<AST::TupleExpr> (
8944 new AST::TupleExpr (std::vector<std::unique_ptr<AST::Expr>> (),
8945 std::move (inner_attrs), std::move (outer_attrs),
8946 locus));
8947 }
8948
8949 // parse first expression (required)
8950 std::unique_ptr<AST::Expr> first_expr = parse_expr ();
8951 if (first_expr == nullptr)
8952 {
8953 Error error (lexer.peek_token ()->get_locus (),
8954 "failed to parse expression in grouped or tuple expression");
8955 add_error (std::move (error));
8956
8957 // skip after somewhere?
8958 return nullptr;
8959 }
8960
8961 // detect whether grouped expression with right parentheses as next token
8962 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
8963 {
8964 // must be grouped expr
8965 lexer.skip_token ();
8966
8967 // create grouped expr
8968 return std::unique_ptr<AST::GroupedExpr> (
8969 new AST::GroupedExpr (std::move (first_expr), std::move (inner_attrs),
8970 std::move (outer_attrs), locus));
8971 }
8972 else if (lexer.peek_token ()->get_id () == COMMA)
8973 {
8974 // tuple expr
8975 std::vector<std::unique_ptr<AST::Expr>> exprs;
8976 exprs.push_back (std::move (first_expr));
8977
8978 // parse potential other tuple exprs
8979 const_TokenPtr t = lexer.peek_token ();
8980 while (t->get_id () == COMMA)
8981 {
8982 lexer.skip_token ();
8983
8984 // break out if right paren
8985 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
8986 break;
8987
8988 // parse expr, which is now required
8989 std::unique_ptr<AST::Expr> expr = parse_expr ();
8990 if (expr == nullptr)
8991 {
8992 Error error (lexer.peek_token ()->get_locus (),
8993 "failed to parse expr in tuple expr");
8994 add_error (std::move (error));
8995
8996 // skip somewhere?
8997 return nullptr;
8998 }
8999 exprs.push_back (std::move (expr));
9000
9001 t = lexer.peek_token ();
9002 }
9003
9004 // skip right paren
9005 skip_token (RIGHT_PAREN);
9006
9007 return std::unique_ptr<AST::TupleExpr> (
9008 new AST::TupleExpr (std::move (exprs), std::move (inner_attrs),
9009 std::move (outer_attrs), locus));
9010 }
9011 else
9012 {
9013 // error
9014 const_TokenPtr t = lexer.peek_token ();
9015 Error error (t->get_locus (),
9016 "unexpected token %qs in grouped or tuple expression "
9017 "(parenthesised expression) - expected %<)%> for grouped "
9018 "expr and %<,%> for tuple expr",
9019 t->get_token_description ());
9020 add_error (std::move (error));
9021
9022 // skip somewhere?
9023 return nullptr;
9024 }
9025}
9026
9027// Parses a type (will further disambiguate any type).
9028template <typename ManagedTokenSource>
9029std::unique_ptr<AST::Type>
9030Parser<ManagedTokenSource>::parse_type (bool save_errors)
9031{
9032 /* rules for all types:
9033 * NeverType: '!'
9034 * SliceType: '[' Type ']'
9035 * InferredType: '_'
9036 * MacroInvocation: SimplePath '!' DelimTokenTree
9037 * ParenthesisedType: '(' Type ')'
9038 * ImplTraitType: 'impl' TypeParamBounds
9039 * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'?
9040 * TypeParamBound Lifetime | TraitBound
9041 * ImplTraitTypeOneBound: 'impl' TraitBound
9042 * TraitObjectType: 'dyn'? TypeParamBounds
9043 * TraitObjectTypeOneBound: 'dyn'? TraitBound
9044 * TraitBound '?'? ForLifetimes? TypePath | '(' '?'?
9045 * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes?
9046 * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
9047 * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )?
9048 * 'unsafe'?
9049 * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>'
9050 * (
9051 * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment (
9052 * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']'
9053 * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds
9054 * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds
9055 * TupleType: '(' Type etc. - regular tuple stuff. Also
9056 * regular tuple vs parenthesised precedence
9057 *
9058 * Disambiguate between macro and type path via type path being parsed, and
9059 * then if '!' found, convert type path to simple path for macro. Usual
9060 * disambiguation for tuple vs parenthesised. For ImplTraitType and
9061 * TraitObjectType individual disambiguations, they seem more like "special
9062 * cases", so probably just try to parse the more general ImplTraitType or
9063 * TraitObjectType and return OneBound versions if they satisfy those
9064 * criteria. */
9065
9066 const_TokenPtr t = lexer.peek_token ();
9067 switch (t->get_id ())
9068 {
9069 case EXCLAM:
9070 // never type - can't be macro as no path beforehand
9071 lexer.skip_token ();
9072 return std::unique_ptr<AST::NeverType> (
9073 new AST::NeverType (t->get_locus ()));
9074 case LEFT_SQUARE:
9075 // slice type or array type - requires further disambiguation
9076 return parse_slice_or_array_type ();
9077 case LEFT_ANGLE: {
9078 // qualified path in type
9079 AST::QualifiedPathInType path = parse_qualified_path_in_type ();
9080 if (path.is_error ())
9081 {
9082 if (save_errors)
9083 {
9084 Error error (t->get_locus (),
9085 "failed to parse qualified path in type");
9086 add_error (std::move (error));
9087 }
9088
9089 return nullptr;
9090 }
9091 return std::unique_ptr<AST::QualifiedPathInType> (
9092 new AST::QualifiedPathInType (std::move (path)));
9093 }
9094 case UNDERSCORE:
9095 // inferred type
9096 lexer.skip_token ();
9097 return std::unique_ptr<AST::InferredType> (
9098 new AST::InferredType (t->get_locus ()));
9099 case ASTERISK:
9100 // raw pointer type
9101 return parse_raw_pointer_type ();
9102 case AMP: // does this also include AMP_AMP?
9103 // reference type
9104 return parse_reference_type ();
9105 case LIFETIME: {
9106 /* probably a lifetime bound, so probably type param bounds in
9107 * TraitObjectType */
9108 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
9109 = parse_type_param_bounds ();
9110
9111 return std::unique_ptr<AST::TraitObjectType> (
9112 new AST::TraitObjectType (std::move (bounds), t->get_locus (),
9113 false));
9114 }
9115 case IDENTIFIER:
9116 case SUPER:
9117 case SELF:
9118 case SELF_ALIAS:
9119 case CRATE:
9120 case DOLLAR_SIGN:
9121 case SCOPE_RESOLUTION: {
9122 // macro invocation or type path - requires further disambiguation.
9123 /* for parsing path component of each rule, perhaps parse it as a
9124 * typepath and attempt conversion to simplepath if a trailing '!' is
9125 * found */
9126 /* Type path also includes TraitObjectTypeOneBound BUT if it starts
9127 * with it, it is exactly the same as a TypePath syntactically, so
9128 * this is a syntactical ambiguity. As such, the parser will parse it
9129 * as a TypePath. This, however, does not prevent TraitObjectType from
9130 * starting with a typepath. */
9131
9132 // parse path as type path
9133 AST::TypePath path = parse_type_path ();
9134 if (path.is_error ())
9135 {
9136 if (save_errors)
9137 {
9138 Error error (t->get_locus (),
9139 "failed to parse path as first component of type");
9140 add_error (std::move (error));
9141 }
9142
9143 return nullptr;
9144 }
9145 Location locus = path.get_locus ();
9146
9147 // branch on next token
9148 t = lexer.peek_token ();
9149 switch (t->get_id ())
9150 {
9151 case EXCLAM: {
9152 // macro invocation
9153 // convert to simple path
9154 AST::SimplePath macro_path = path.as_simple_path ();
9155 if (macro_path.is_empty ())
9156 {
9157 if (save_errors)
9158 {
9159 Error error (t->get_locus (),
9160 "failed to parse simple path in macro "
9161 "invocation (for type)");
9162 add_error (std::move (error));
9163 }
9164
9165 return nullptr;
9166 }
9167
9168 lexer.skip_token ();
9169
9170 AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
9171
9172 return std::unique_ptr<AST::MacroInvocation> (
9173 new AST::MacroInvocation (
9174 AST::MacroInvocData (std::move (macro_path),
9175 std::move (tok_tree)),
9176 {}, locus));
9177 }
9178 case PLUS: {
9179 // type param bounds
9180 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9181
9182 // convert type path to trait bound
9183 std::unique_ptr<AST::TraitBound> path_bound (
9184 new AST::TraitBound (std::move (path), locus, false, false));
9185 bounds.push_back (std::move (path_bound));
9186
9187 /* parse rest of bounds - FIXME: better way to find when to stop
9188 * parsing */
9189 while (t->get_id () == PLUS)
9190 {
9191 lexer.skip_token ();
9192
9193 // parse bound if it exists - if not, assume end of sequence
9194 std::unique_ptr<AST::TypeParamBound> bound
9195 = parse_type_param_bound ();
9196 if (bound == nullptr)
9197 {
9198 break;
9199 }
9200 bounds.push_back (std::move (bound));
9201
9202 t = lexer.peek_token ();
9203 }
9204
9205 return std::unique_ptr<AST::TraitObjectType> (
9206 new AST::TraitObjectType (std::move (bounds), locus, false));
9207 }
9208 default:
9209 // assume that this is a type path and not an error
9210 return std::unique_ptr<AST::TypePath> (
9211 new AST::TypePath (std::move (path)));
9212 }
9213 }
9214 case LEFT_PAREN:
9215 /* tuple type or parenthesised type - requires further disambiguation
9216 * (the usual). ok apparently can be a parenthesised TraitBound too, so
9217 * could be TraitObjectTypeOneBound or TraitObjectType */
9218 return parse_paren_prefixed_type ();
9219 case FOR:
9220 // TraitObjectTypeOneBound or BareFunctionType
9221 return parse_for_prefixed_type ();
9222 case ASYNC:
9223 case CONST:
9224 case UNSAFE:
9225 case EXTERN_TOK:
9226 case FN_TOK:
9227 // bare function type (with no for lifetimes)
9228 return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
9229 case IMPL:
9230 lexer.skip_token ();
9231 if (lexer.peek_token ()->get_id () == LIFETIME)
9232 {
9233 /* cannot be one bound because lifetime prevents it from being
9234 * traitbound */
9235 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
9236 = parse_type_param_bounds ();
9237
9238 return std::unique_ptr<AST::ImplTraitType> (
9239 new AST::ImplTraitType (std::move (bounds), t->get_locus ()));
9240 }
9241 else
9242 {
9243 // should be trait bound, so parse trait bound
9244 std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
9245 if (initial_bound == nullptr)
9246 {
9247 if (save_errors)
9248 {
9249 Error error (lexer.peek_token ()->get_locus (),
9250 "failed to parse ImplTraitType initial bound");
9251 add_error (std::move (error));
9252 }
9253
9254 return nullptr;
9255 }
9256
9257 Location locus = t->get_locus ();
9258
9259 // short cut if next token isn't '+'
9260 t = lexer.peek_token ();
9261 if (t->get_id () != PLUS)
9262 {
9263 // convert trait bound to value object
9264 AST::TraitBound value_bound (*initial_bound);
9265
9266 // DEBUG: removed as unique ptr, so should auto-delete
9267 // delete initial_bound;
9268
9269 return std::unique_ptr<AST::ImplTraitTypeOneBound> (
9270 new AST::ImplTraitTypeOneBound (std::move (value_bound),
9271 locus));
9272 }
9273
9274 // parse additional type param bounds
9275 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9276 bounds.push_back (std::move (initial_bound));
9277 while (t->get_id () == PLUS)
9278 {
9279 lexer.skip_token ();
9280
9281 // parse bound if it exists
9282 std::unique_ptr<AST::TypeParamBound> bound
9283 = parse_type_param_bound ();
9284 if (bound == nullptr)
9285 {
9286 // not an error as trailing plus may exist
9287 break;
9288 }
9289 bounds.push_back (std::move (bound));
9290
9291 t = lexer.peek_token ();
9292 }
9293
9294 return std::unique_ptr<AST::ImplTraitType> (
9295 new AST::ImplTraitType (std::move (bounds), locus));
9296 }
9297 case DYN:
9298 case QUESTION_MARK: {
9299 // either TraitObjectType or TraitObjectTypeOneBound
9300 bool has_dyn = false;
9301 if (t->get_id () == DYN)
9302 {
9303 lexer.skip_token ();
9304 has_dyn = true;
9305 }
9306
9307 if (lexer.peek_token ()->get_id () == LIFETIME)
9308 {
9309 /* cannot be one bound because lifetime prevents it from being
9310 * traitbound */
9311 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds
9312 = parse_type_param_bounds ();
9313
9314 return std::unique_ptr<AST::TraitObjectType> (
9315 new AST::TraitObjectType (std::move (bounds), t->get_locus (),
9316 has_dyn));
9317 }
9318 else
9319 {
9320 // should be trait bound, so parse trait bound
9321 std::unique_ptr<AST::TraitBound> initial_bound
9322 = parse_trait_bound ();
9323 if (initial_bound == nullptr)
9324 {
9325 if (save_errors)
9326 {
9327 Error error (
9328 lexer.peek_token ()->get_locus (),
9329 "failed to parse TraitObjectType initial bound");
9330 add_error (std::move (error));
9331 }
9332
9333 return nullptr;
9334 }
9335
9336 // short cut if next token isn't '+'
9337 t = lexer.peek_token ();
9338 if (t->get_id () != PLUS)
9339 {
9340 // convert trait bound to value object
9341 AST::TraitBound value_bound (*initial_bound);
9342
9343 // DEBUG: removed as unique ptr, so should auto delete
9344 // delete initial_bound;
9345
9346 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
9347 new AST::TraitObjectTypeOneBound (std::move (value_bound),
9348 t->get_locus (), has_dyn));
9349 }
9350
9351 // parse additional type param bounds
9352 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9353 bounds.push_back (std::move (initial_bound));
9354 while (t->get_id () == PLUS)
9355 {
9356 lexer.skip_token ();
9357
9358 // parse bound if it exists
9359 std::unique_ptr<AST::TypeParamBound> bound
9360 = parse_type_param_bound ();
9361 if (bound == nullptr)
9362 {
9363 // not an error as trailing plus may exist
9364 break;
9365 }
9366 bounds.push_back (std::move (bound));
9367
9368 t = lexer.peek_token ();
9369 }
9370
9371 return std::unique_ptr<AST::TraitObjectType> (
9372 new AST::TraitObjectType (std::move (bounds), t->get_locus (),
9373 has_dyn));
9374 }
9375 }
9376 default:
9377 if (save_errors)
9378 add_error (Error (t->get_locus (), "unrecognised token %qs in type",
9379 t->get_token_description ()));
9380
9381 return nullptr;
9382 }
9383}
9384
9385/* Parses a type that has '(' as its first character. Returns a tuple type,
9386 * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
9387 * on following characters. */
9388template <typename ManagedTokenSource>
9389std::unique_ptr<AST::Type>
9390Parser<ManagedTokenSource>::parse_paren_prefixed_type ()
9391{
9392 /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
9393 * a trait bound, not a parenthesised type, so that it can still be used in
9394 * type param bounds. */
9395
9396 /* NOTE: this implementation is really shit but I couldn't think of a better
9397 * one. It requires essentially breaking polymorphism and downcasting via
9398 * virtual method abuse, as it was copied from the rustc implementation (in
9399 * which types are reified due to tagged union), after a more OOP attempt by
9400 * me failed. */
9401 Location left_delim_locus = lexer.peek_token ()->get_locus ();
9402
9403 // skip left delim
9404 lexer.skip_token ();
9405 /* while next token isn't close delim, parse comma-separated types, saving
9406 * whether trailing comma happens */
9407 const_TokenPtr t = lexer.peek_token ();
9408 bool trailing_comma = true;
9409 std::vector<std::unique_ptr<AST::Type>> types;
9410
9411 while (t->get_id () != RIGHT_PAREN)
9412 {
9413 std::unique_ptr<AST::Type> type = parse_type ();
9414 if (type == nullptr)
9415 {
9416 Error error (t->get_locus (),
9417 "failed to parse type inside parentheses (probably "
9418 "tuple or parenthesised)");
9419 add_error (std::move (error));
9420
9421 return nullptr;
9422 }
9423 types.push_back (std::move (type));
9424
9425 t = lexer.peek_token ();
9426 if (t->get_id () != COMMA)
9427 {
9428 trailing_comma = false;
9429 break;
9430 }
9431 lexer.skip_token ();
9432
9433 t = lexer.peek_token ();
9434 }
9435
9436 if (!skip_token (RIGHT_PAREN))
9437 {
9438 return nullptr;
9439 }
9440
9441 // if only one type and no trailing comma, then not a tuple type
9442 if (types.size () == 1 && !trailing_comma)
9443 {
9444 // must be a TraitObjectType (with more than one bound)
9445 if (lexer.peek_token ()->get_id () == PLUS)
9446 {
9447 // create type param bounds vector
9448 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9449
9450 // HACK: convert type to traitbound and add to bounds
9451 std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
9452 std::unique_ptr<AST::TraitBound> converted_bound (
9453 released_ptr->to_trait_bound (true));
9454 if (converted_bound == nullptr)
9455 {
9456 Error error (
9457 lexer.peek_token ()->get_locus (),
9458 "failed to hackily converted parsed type to trait bound");
9459 add_error (std::move (error));
9460
9461 return nullptr;
9462 }
9463 bounds.push_back (std::move (converted_bound));
9464
9465 t = lexer.peek_token ();
9466 while (t->get_id () == PLUS)
9467 {
9468 lexer.skip_token ();
9469
9470 // attempt to parse typeparambound
9471 std::unique_ptr<AST::TypeParamBound> bound
9472 = parse_type_param_bound ();
9473 if (bound == nullptr)
9474 {
9475 // not an error if null
9476 break;
9477 }
9478 bounds.push_back (std::move (bound));
9479
9480 t = lexer.peek_token ();
9481 }
9482
9483 return std::unique_ptr<AST::TraitObjectType> (
9484 new AST::TraitObjectType (std::move (bounds), left_delim_locus,
9485 false));
9486 }
9487 else
9488 {
9489 // release vector pointer
9490 std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
9491 /* HACK: attempt to convert to trait bound. if fails, parenthesised
9492 * type */
9493 std::unique_ptr<AST::TraitBound> converted_bound (
9494 released_ptr->to_trait_bound (true));
9495 if (converted_bound == nullptr)
9496 {
9497 // parenthesised type
9498 return std::unique_ptr<AST::ParenthesisedType> (
9499 new AST::ParenthesisedType (std::move (released_ptr),
9500 left_delim_locus));
9501 }
9502 else
9503 {
9504 // trait object type (one bound)
9505
9506 // get value semantics trait bound
9507 AST::TraitBound value_bound (*converted_bound);
9508
9509 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
9510 new AST::TraitObjectTypeOneBound (value_bound,
9511 left_delim_locus));
9512 }
9513 }
9514 }
9515 else
9516 {
9517 return std::unique_ptr<AST::TupleType> (
9518 new AST::TupleType (std::move (types), left_delim_locus));
9519 }
9520 /* TODO: ensure that this ensures that dynamic dispatch for traits is not
9521 * lost somehow */
9522}
9523
9524/* Parses a type that has 'for' as its first character. This means it has a
9525 * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
9526 * TraitObjectTypeOneBound depending on following characters. */
9527template <typename ManagedTokenSource>
9528std::unique_ptr<AST::Type>
9529Parser<ManagedTokenSource>::parse_for_prefixed_type ()
9530{
9531 Location for_locus = lexer.peek_token ()->get_locus ();
9532 // parse for lifetimes in type
9533 std::vector<AST::LifetimeParam> for_lifetimes = parse_for_lifetimes ();
9534
9535 // branch on next token - either function or a trait type
9536 const_TokenPtr t = lexer.peek_token ();
9537 switch (t->get_id ())
9538 {
9539 case ASYNC:
9540 case CONST:
9541 case UNSAFE:
9542 case EXTERN_TOK:
9543 case FN_TOK:
9544 return parse_bare_function_type (std::move (for_lifetimes));
9545 case SCOPE_RESOLUTION:
9546 case IDENTIFIER:
9547 case SUPER:
9548 case SELF:
9549 case SELF_ALIAS:
9550 case CRATE:
9551 case DOLLAR_SIGN: {
9552 // path, so trait type
9553
9554 // parse type path to finish parsing trait bound
9555 AST::TypePath path = parse_type_path ();
9556
9557 t = lexer.peek_token ();
9558 if (t->get_id () != PLUS)
9559 {
9560 // must be one-bound trait type
9561 // create trait bound value object
9562 AST::TraitBound bound (std::move (path), for_locus, false, false,
9563 std::move (for_lifetimes));
9564
9565 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
9566 new AST::TraitObjectTypeOneBound (std::move (bound), for_locus));
9567 }
9568
9569 /* more than one bound trait type (or at least parsed as it - could be
9570 * trailing '+') create trait bound pointer and bounds */
9571 std::unique_ptr<AST::TraitBound> initial_bound (
9572 new AST::TraitBound (std::move (path), for_locus, false, false,
9573 std::move (for_lifetimes)));
9574 std::vector<std::unique_ptr<AST::TypeParamBound>> bounds;
9575 bounds.push_back (std::move (initial_bound));
9576
9577 while (t->get_id () == PLUS)
9578 {
9579 lexer.skip_token ();
9580
9581 // parse type param bound if it exists
9582 std::unique_ptr<AST::TypeParamBound> bound
9583 = parse_type_param_bound ();
9584 if (bound == nullptr)
9585 {
9586 // not an error - e.g. trailing plus
9587 return nullptr;
9588 }
9589 bounds.push_back (std::move (bound));
9590
9591 t = lexer.peek_token ();
9592 }
9593
9594 return std::unique_ptr<AST::TraitObjectType> (
9595 new AST::TraitObjectType (std::move (bounds), for_locus, false));
9596 }
9597 default:
9598 // error
9599 add_error (Error (t->get_locus (),
9600 "unrecognised token %qs in bare function type or trait "
9601 "object type or trait object type one bound",
9602 t->get_token_description ()));
9603
9604 return nullptr;
9605 }
9606}
9607
9608// Parses a maybe named param used in bare function types.
9609template <typename ManagedTokenSource>
9610AST::MaybeNamedParam
9611Parser<ManagedTokenSource>::parse_maybe_named_param (AST::AttrVec outer_attrs)
9612{
9613 /* Basically guess that param is named if first token is identifier or
9614 * underscore and second token is semicolon. This should probably have no
9615 * exceptions. rustc uses backtracking to parse these, but at the time of
9616 * writing gccrs has no backtracking capabilities. */
9617 const_TokenPtr current = lexer.peek_token ();
9618 const_TokenPtr next = lexer.peek_token (1);
9619
9620 Identifier name;
9621 AST::MaybeNamedParam::ParamKind kind = AST::MaybeNamedParam::UNNAMED;
9622
9623 if (current->get_id () == IDENTIFIER && next->get_id () == COLON)
9624 {
9625 // named param
9626 name = current->get_str ();
9627 kind = AST::MaybeNamedParam::IDENTIFIER;
9628 lexer.skip_token (1);
9629 }
9630 else if (current->get_id () == UNDERSCORE && next->get_id () == COLON)
9631 {
9632 // wildcard param
9633 name = "_";
9634 kind = AST::MaybeNamedParam::WILDCARD;
9635 lexer.skip_token (1);
9636 }
9637
9638 // parse type (required)
9639 std::unique_ptr<AST::Type> type = parse_type ();
9640 if (type == nullptr)
9641 {
9642 Error error (lexer.peek_token ()->get_locus (),
9643 "failed to parse type in maybe named param");
9644 add_error (std::move (error));
9645
9646 return AST::MaybeNamedParam::create_error ();
9647 }
9648
9649 return AST::MaybeNamedParam (std::move (name), kind, std::move (type),
9650 std::move (outer_attrs), current->get_locus ());
9651}
9652
9653/* Parses a bare function type (with the given for lifetimes for convenience -
9654 * does not parse them itself). */
9655template <typename ManagedTokenSource>
9656std::unique_ptr<AST::BareFunctionType>
9657Parser<ManagedTokenSource>::parse_bare_function_type (
9658 std::vector<AST::LifetimeParam> for_lifetimes)
9659{
9660 // TODO: pass in for lifetime location as param
9661 Location best_try_locus = lexer.peek_token ()->get_locus ();
9662
9663 AST::FunctionQualifiers qualifiers = parse_function_qualifiers ();
9664
9665 if (!skip_token (FN_TOK))
9666 return nullptr;
9667
9668 if (!skip_token (LEFT_PAREN))
9669 return nullptr;
9670
9671 // parse function params, if they exist
9672 std::vector<AST::MaybeNamedParam> params;
9673 bool is_variadic = false;
9674 AST::AttrVec variadic_attrs;
9675
9676 const_TokenPtr t = lexer.peek_token ();
9677 while (t->get_id () != RIGHT_PAREN)
9678 {
9679 AST::AttrVec temp_attrs = parse_outer_attributes ();
9680
9681 if (lexer.peek_token ()->get_id () == ELLIPSIS)
9682 {
9683 lexer.skip_token ();
9684 is_variadic = true;
9685 variadic_attrs = std::move (temp_attrs);
9686
9687 t = lexer.peek_token ();
9688
9689 if (t->get_id () != RIGHT_PAREN)
9690 {
9691 Error error (t->get_locus (),
9692 "expected right parentheses after variadic in maybe "
9693 "named function "
9694 "parameters, found %qs",
9695 t->get_token_description ());
9696 add_error (std::move (error));
9697
9698 return nullptr;
9699 }
9700
9701 break;
9702 }
9703
9704 AST::MaybeNamedParam param
9705 = parse_maybe_named_param (std::move (temp_attrs));
9706 if (param.is_error ())
9707 {
9708 Error error (
9709 lexer.peek_token ()->get_locus (),
9710 "failed to parse maybe named param in bare function type");
9711 add_error (std::move (error));
9712
9713 return nullptr;
9714 }
9715 params.push_back (std::move (param));
9716
9717 if (lexer.peek_token ()->get_id () != COMMA)
9718 break;
9719
9720 lexer.skip_token ();
9721 t = lexer.peek_token ();
9722 }
9723
9724 if (!skip_token (RIGHT_PAREN))
9725 return nullptr;
9726
9727 // bare function return type, if exists
9728 std::unique_ptr<AST::TypeNoBounds> return_type = nullptr;
9729 if (lexer.peek_token ()->get_id () == RETURN_TYPE)
9730 {
9731 lexer.skip_token ();
9732
9733 // parse required TypeNoBounds
9734 return_type = parse_type_no_bounds ();
9735 if (return_type == nullptr)
9736 {
9737 Error error (lexer.peek_token ()->get_locus (),
9738 "failed to parse return type (type no bounds) in bare "
9739 "function type");
9740 add_error (std::move (error));
9741
9742 return nullptr;
9743 }
9744 }
9745
9746 return std::unique_ptr<AST::BareFunctionType> (
9747 new AST::BareFunctionType (std::move (for_lifetimes),
9748 std::move (qualifiers), std::move (params),
9749 is_variadic, std::move (variadic_attrs),
9750 std::move (return_type), best_try_locus));
9751}
9752
9753// Parses a reference type (mutable or immutable, with given lifetime).
9754template <typename ManagedTokenSource>
9755std::unique_ptr<AST::ReferenceType>
9756Parser<ManagedTokenSource>::parse_reference_type ()
9757{
9758 Location locus = lexer.peek_token ()->get_locus ();
9759 skip_token (AMP);
9760
9761 // parse optional lifetime
9762 AST::Lifetime lifetime = AST::Lifetime::error ();
9763 if (lexer.peek_token ()->get_id () == LIFETIME)
9764 {
9765 lifetime = parse_lifetime ();
9766 if (lifetime.is_error ())
9767 {
9768 Error error (lexer.peek_token ()->get_locus (),
9769 "failed to parse lifetime in reference type");
9770 add_error (std::move (error));
9771
9772 return nullptr;
9773 }
9774 }
9775
9776 bool is_mut = false;
9777 if (lexer.peek_token ()->get_id () == MUT)
9778 {
9779 lexer.skip_token ();
9780 is_mut = true;
9781 }
9782
9783 // parse type no bounds, which is required
9784 std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
9785 if (type == nullptr)
9786 {
9787 Error error (lexer.peek_token ()->get_locus (),
9788 "failed to parse referenced type in reference type");
9789 add_error (std::move (error));
9790
9791 return nullptr;
9792 }
9793
9794 return std::unique_ptr<AST::ReferenceType> (
9795 new AST::ReferenceType (is_mut, std::move (type), locus,
9796 std::move (lifetime)));
9797}
9798
9799// Parses a raw (unsafe) pointer type.
9800template <typename ManagedTokenSource>
9801std::unique_ptr<AST::RawPointerType>
9802Parser<ManagedTokenSource>::parse_raw_pointer_type ()
9803{
9804 Location locus = lexer.peek_token ()->get_locus ();
9805 skip_token (ASTERISK);
9806
9807 AST::RawPointerType::PointerType kind = AST::RawPointerType::CONST;
9808
9809 // branch on next token for pointer kind info
9810 const_TokenPtr t = lexer.peek_token ();
9811 switch (t->get_id ())
9812 {
9813 case MUT:
9814 kind = AST::RawPointerType::MUT;
9815 lexer.skip_token ();
9816 break;
9817 case CONST:
9818 kind = AST::RawPointerType::CONST;
9819 lexer.skip_token ();
9820 break;
9821 default:
9822 add_error (Error (t->get_locus (),
9823 "unrecognised token %qs in raw pointer type",
9824 t->get_token_description ()));
9825
9826 return nullptr;
9827 }
9828
9829 // parse type no bounds (required)
9830 std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
9831 if (type == nullptr)
9832 {
9833 Error error (lexer.peek_token ()->get_locus (),
9834 "failed to parse pointed type of raw pointer type");
9835 add_error (std::move (error));
9836
9837 return nullptr;
9838 }
9839
9840 return std::unique_ptr<AST::RawPointerType> (
9841 new AST::RawPointerType (kind, std::move (type), locus));
9842}
9843
9844/* Parses a slice or array type, depending on following arguments (as
9845 * lookahead is not possible). */
9846template <typename ManagedTokenSource>
9847std::unique_ptr<AST::TypeNoBounds>
9848Parser<ManagedTokenSource>::parse_slice_or_array_type ()
9849{
9850 Location locus = lexer.peek_token ()->get_locus ();
9851 skip_token (LEFT_SQUARE);
9852
9853 // parse inner type (required)
9854 std::unique_ptr<AST::Type> inner_type = parse_type ();
9855 if (inner_type == nullptr)
9856 {
9857 Error error (lexer.peek_token ()->get_locus (),
9858 "failed to parse inner type in slice or array type");
9859 add_error (std::move (error));
9860
9861 return nullptr;
9862 }
9863
9864 // branch on next token
9865 const_TokenPtr t = lexer.peek_token ();
9866 switch (t->get_id ())
9867 {
9868 case RIGHT_SQUARE:
9869 // slice type
9870 lexer.skip_token ();
9871
9872 return std::unique_ptr<AST::SliceType> (
9873 new AST::SliceType (std::move (inner_type), locus));
9874 case SEMICOLON: {
9875 // array type
9876 lexer.skip_token ();
9877
9878 // parse required array size expression
9879 std::unique_ptr<AST::Expr> size = parse_expr ();
9880 if (size == nullptr)
9881 {
9882 Error error (lexer.peek_token ()->get_locus (),
9883 "failed to parse size expression in array type");
9884 add_error (std::move (error));
9885
9886 return nullptr;
9887 }
9888
9889 if (!skip_token (RIGHT_SQUARE))
9890 {
9891 return nullptr;
9892 }
9893
9894 return std::unique_ptr<AST::ArrayType> (
9895 new AST::ArrayType (std::move (inner_type), std::move (size), locus));
9896 }
9897 default:
9898 // error
9899 add_error (
9900 Error (t->get_locus (),
9901 "unrecognised token %qs in slice or array type after inner type",
9902 t->get_token_description ()));
9903
9904 return nullptr;
9905 }
9906}
9907
9908// Parses a type, taking into account type boundary disambiguation.
9909template <typename ManagedTokenSource>
9910std::unique_ptr<AST::TypeNoBounds>
9911Parser<ManagedTokenSource>::parse_type_no_bounds ()
9912{
9913 const_TokenPtr t = lexer.peek_token ();
9914 switch (t->get_id ())
9915 {
9916 case EXCLAM:
9917 // never type - can't be macro as no path beforehand
9918 lexer.skip_token ();
9919 return std::unique_ptr<AST::NeverType> (
9920 new AST::NeverType (t->get_locus ()));
9921 case LEFT_SQUARE:
9922 // slice type or array type - requires further disambiguation
9923 return parse_slice_or_array_type ();
9924 case LEFT_ANGLE: {
9925 // qualified path in type
9926 AST::QualifiedPathInType path = parse_qualified_path_in_type ();
9927 if (path.is_error ())
9928 {
9929 Error error (t->get_locus (),
9930 "failed to parse qualified path in type");
9931 add_error (std::move (error));
9932
9933 return nullptr;
9934 }
9935 return std::unique_ptr<AST::QualifiedPathInType> (
9936 new AST::QualifiedPathInType (std::move (path)));
9937 }
9938 case UNDERSCORE:
9939 // inferred type
9940 lexer.skip_token ();
9941 return std::unique_ptr<AST::InferredType> (
9942 new AST::InferredType (t->get_locus ()));
9943 case ASTERISK:
9944 // raw pointer type
9945 return parse_raw_pointer_type ();
9946 case AMP: // does this also include AMP_AMP?
9947 // reference type
9948 return parse_reference_type ();
9949 case LIFETIME:
9950 /* probably a lifetime bound, so probably type param bounds in
9951 * TraitObjectType. this is not allowed, but detection here for error
9952 * message */
9953 add_error (Error (t->get_locus (),
9954 "lifetime bounds (i.e. in type param bounds, in "
9955 "TraitObjectType) are not allowed as TypeNoBounds"));
9956
9957 return nullptr;
9958 case IDENTIFIER:
9959 case SUPER:
9960 case SELF:
9961 case SELF_ALIAS:
9962 case CRATE:
9963 case DOLLAR_SIGN:
9964 case SCOPE_RESOLUTION: {
9965 // macro invocation or type path - requires further disambiguation.
9966 /* for parsing path component of each rule, perhaps parse it as a
9967 * typepath and attempt conversion to simplepath if a trailing '!' is
9968 * found */
9969 /* Type path also includes TraitObjectTypeOneBound BUT if it starts
9970 * with it, it is exactly the same as a TypePath syntactically, so
9971 * this is a syntactical ambiguity. As such, the parser will parse it
9972 * as a TypePath. This, however, does not prevent TraitObjectType from
9973 * starting with a typepath. */
9974
9975 // parse path as type path
9976 AST::TypePath path = parse_type_path ();
9977 if (path.is_error ())
9978 {
9979 Error error (
9980 t->get_locus (),
9981 "failed to parse path as first component of type no bounds");
9982 add_error (std::move (error));
9983
9984 return nullptr;
9985 }
9986 Location locus = path.get_locus ();
9987
9988 // branch on next token
9989 t = lexer.peek_token ();
9990 switch (t->get_id ())
9991 {
9992 case EXCLAM: {
9993 // macro invocation
9994 // convert to simple path
9995 AST::SimplePath macro_path = path.as_simple_path ();
9996 if (macro_path.is_empty ())
9997 {
9998 Error error (t->get_locus (),
9999 "failed to parse simple path in macro "
10000 "invocation (for type)");
10001 add_error (std::move (error));
10002
10003 return nullptr;
10004 }
10005
10006 lexer.skip_token ();
10007
10008 AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
10009
10010 return std::unique_ptr<AST::MacroInvocation> (
10011 new AST::MacroInvocation (
10012 AST::MacroInvocData (std::move (macro_path),
10013 std::move (tok_tree)),
10014 {}, locus));
10015 }
10016 default:
10017 // assume that this is a type path and not an error
10018 return std::unique_ptr<AST::TypePath> (
10019 new AST::TypePath (std::move (path)));
10020 }
10021 }
10022 case LEFT_PAREN:
10023 /* tuple type or parenthesised type - requires further disambiguation
10024 * (the usual). ok apparently can be a parenthesised TraitBound too, so
10025 * could be TraitObjectTypeOneBound */
10026 return parse_paren_prefixed_type_no_bounds ();
10027 case FOR:
10028 case ASYNC:
10029 case CONST:
10030 case UNSAFE:
10031 case EXTERN_TOK:
10032 case FN_TOK:
10033 // bare function type (with no for lifetimes)
10034 return parse_bare_function_type (std::vector<AST::LifetimeParam> ());
10035 case IMPL:
10036 lexer.skip_token ();
10037 if (lexer.peek_token ()->get_id () == LIFETIME)
10038 {
10039 /* cannot be one bound because lifetime prevents it from being
10040 * traitbound not allowed as type no bounds, only here for error
10041 * message */
10042 Error error (
10043 lexer.peek_token ()->get_locus (),
10044 "lifetime (probably lifetime bound, in type param "
10045 "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
10046 add_error (std::move (error));
10047
10048 return nullptr;
10049 }
10050 else
10051 {
10052 // should be trait bound, so parse trait bound
10053 std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
10054 if (initial_bound == nullptr)
10055 {
10056 Error error (lexer.peek_token ()->get_locus (),
10057 "failed to parse ImplTraitTypeOneBound bound");
10058 add_error (std::move (error));
10059
10060 return nullptr;
10061 }
10062
10063 Location locus = t->get_locus ();
10064
10065 // ensure not a trait with multiple bounds
10066 t = lexer.peek_token ();
10067 if (t->get_id () == PLUS)
10068 {
10069 Error error (t->get_locus (),
10070 "plus after trait bound means an ImplTraitType, "
10071 "which is not allowed as a TypeNoBounds");
10072 add_error (std::move (error));
10073
10074 return nullptr;
10075 }
10076
10077 // convert trait bound to value object
10078 AST::TraitBound value_bound (*initial_bound);
10079
10080 return std::unique_ptr<AST::ImplTraitTypeOneBound> (
10081 new AST::ImplTraitTypeOneBound (std::move (value_bound), locus));
10082 }
10083 case DYN:
10084 case QUESTION_MARK: {
10085 // either TraitObjectTypeOneBound
10086 bool has_dyn = false;
10087 if (t->get_id () == DYN)
10088 {
10089 lexer.skip_token ();
10090 has_dyn = true;
10091 }
10092
10093 if (lexer.peek_token ()->get_id () == LIFETIME)
10094 {
10095 /* means that cannot be TraitObjectTypeOneBound - so here for
10096 * error message */
10097 Error error (lexer.peek_token ()->get_locus (),
10098 "lifetime as bound in TraitObjectTypeOneBound "
10099 "is not allowed, so cannot be TypeNoBounds");
10100 add_error (std::move (error));
10101
10102 return nullptr;
10103 }
10104
10105 // should be trait bound, so parse trait bound
10106 std::unique_ptr<AST::TraitBound> initial_bound = parse_trait_bound ();
10107 if (initial_bound == nullptr)
10108 {
10109 Error error (
10110 lexer.peek_token ()->get_locus (),
10111 "failed to parse TraitObjectTypeOneBound initial bound");
10112 add_error (std::move (error));
10113
10114 return nullptr;
10115 }
10116
10117 Location locus = t->get_locus ();
10118
10119 // detect error with plus as next token
10120 t = lexer.peek_token ();
10121 if (t->get_id () == PLUS)
10122 {
10123 Error error (t->get_locus (),
10124 "plus after trait bound means a TraitObjectType, "
10125 "which is not allowed as a TypeNoBounds");
10126 add_error (std::move (error));
10127
10128 return nullptr;
10129 }
10130
10131 // convert trait bound to value object
10132 AST::TraitBound value_bound (*initial_bound);
10133
10134 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
10135 new AST::TraitObjectTypeOneBound (std::move (value_bound), locus,
10136 has_dyn));
10137 }
10138 default:
10139 add_error (Error (t->get_locus (),
10140 "unrecognised token %qs in type no bounds",
10141 t->get_token_description ()));
10142
10143 return nullptr;
10144 }
10145}
10146
10147// Parses a type no bounds beginning with '('.
10148template <typename ManagedTokenSource>
10149std::unique_ptr<AST::TypeNoBounds>
10150Parser<ManagedTokenSource>::parse_paren_prefixed_type_no_bounds ()
10151{
10152 /* NOTE: this could probably be parsed without the HACK solution of
10153 * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
10154
10155 /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
10156 * considered a trait bound, not a parenthesised type, so that it can still
10157 * be used in type param bounds. */
10158
10159 Location left_paren_locus = lexer.peek_token ()->get_locus ();
10160
10161 // skip left delim
10162 lexer.skip_token ();
10163 /* while next token isn't close delim, parse comma-separated types, saving
10164 * whether trailing comma happens */
10165 const_TokenPtr t = lexer.peek_token ();
10166 bool trailing_comma = true;
10167 std::vector<std::unique_ptr<AST::Type>> types;
10168
10169 while (t->get_id () != RIGHT_PAREN)
10170 {
10171 std::unique_ptr<AST::Type> type = parse_type ();
10172 if (type == nullptr)
10173 {
10174 Error error (t->get_locus (),
10175 "failed to parse type inside parentheses (probably "
10176 "tuple or parenthesised)");
10177 add_error (std::move (error));
10178
10179 return nullptr;
10180 }
10181 types.push_back (std::move (type));
10182
10183 t = lexer.peek_token ();
10184 if (t->get_id () != COMMA)
10185 {
10186 trailing_comma = false;
10187 break;
10188 }
10189 lexer.skip_token ();
10190
10191 t = lexer.peek_token ();
10192 }
10193
10194 if (!skip_token (RIGHT_PAREN))
10195 {
10196 return nullptr;
10197 }
10198
10199 // if only one type and no trailing comma, then not a tuple type
10200 if (types.size () == 1 && !trailing_comma)
10201 {
10202 // must be a TraitObjectType (with more than one bound)
10203 if (lexer.peek_token ()->get_id () == PLUS)
10204 {
10205 // error - this is not allowed for type no bounds
10206 Error error (lexer.peek_token ()->get_locus (),
10207 "plus (implying TraitObjectType as type param "
10208 "bounds) is not allowed in type no bounds");
10209 add_error (std::move (error));
10210
10211 return nullptr;
10212 }
10213 else
10214 {
10215 // release vector pointer
10216 std::unique_ptr<AST::Type> released_ptr = std::move (types[0]);
10217 /* HACK: attempt to convert to trait bound. if fails, parenthesised
10218 * type */
10219 std::unique_ptr<AST::TraitBound> converted_bound (
10220 released_ptr->to_trait_bound (true));
10221 if (converted_bound == nullptr)
10222 {
10223 // parenthesised type
10224 return std::unique_ptr<AST::ParenthesisedType> (
10225 new AST::ParenthesisedType (std::move (released_ptr),
10226 left_paren_locus));
10227 }
10228 else
10229 {
10230 // trait object type (one bound)
10231
10232 // get value semantics trait bound
10233 AST::TraitBound value_bound (*converted_bound);
10234
10235 return std::unique_ptr<AST::TraitObjectTypeOneBound> (
10236 new AST::TraitObjectTypeOneBound (value_bound,
10237 left_paren_locus));
10238 }
10239 }
10240 }
10241 else
10242 {
10243 return std::unique_ptr<AST::TupleType> (
10244 new AST::TupleType (std::move (types), left_paren_locus));
10245 }
10246 /* TODO: ensure that this ensures that dynamic dispatch for traits is not
10247 * lost somehow */
10248}
10249
10250/* Parses a literal pattern or range pattern. Assumes that literals passed in
10251 * are valid range pattern bounds. Do not pass in paths in expressions, for
10252 * instance. */
10253template <typename ManagedTokenSource>
10254std::unique_ptr<AST::Pattern>
10255Parser<ManagedTokenSource>::parse_literal_or_range_pattern ()
10256{
10257 const_TokenPtr range_lower = lexer.peek_token ();
10258 AST::Literal::LitType type = AST::Literal::STRING;
10259 bool has_minus = false;
10260
10261 // get lit type
10262 switch (range_lower->get_id ())
10263 {
10264 case CHAR_LITERAL:
10265 type = AST::Literal::CHAR;
10266 lexer.skip_token ();
10267 break;
10268 case BYTE_CHAR_LITERAL:
10269 type = AST::Literal::BYTE;
10270 lexer.skip_token ();
10271 break;
10272 case INT_LITERAL:
10273 type = AST::Literal::INT;
10274 lexer.skip_token ();
10275 break;
10276 case FLOAT_LITERAL:
10277 type = AST::Literal::FLOAT;
10278 lexer.skip_token ();
10279 break;
10280 case MINUS:
10281 // branch on next token
10282 range_lower = lexer.peek_token (1);
10283 switch (range_lower->get_id ())
10284 {
10285 case INT_LITERAL:
10286 type = AST::Literal::INT;
10287 has_minus = true;
10288 lexer.skip_token (1);
10289 break;
10290 case FLOAT_LITERAL:
10291 type = AST::Literal::FLOAT;
10292 has_minus = true;
10293 lexer.skip_token (1);
10294 break;
10295 default:
10296 add_error (Error (range_lower->get_locus (),
10297 "token type %qs cannot be parsed as range pattern "
10298 "bound or literal after minus symbol",
10299 range_lower->get_token_description ()));
10300
10301 return nullptr;
10302 }
10303 break;
10304 default:
10305 add_error (
10306 Error (range_lower->get_locus (),
10307 "token type %qs cannot be parsed as range pattern bound",
10308 range_lower->get_token_description ()));
10309
10310 return nullptr;
10311 }
10312
10313 const_TokenPtr next = lexer.peek_token ();
10314 if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS)
10315 {
10316 // range pattern
10317 lexer.skip_token ();
10318 std::unique_ptr<AST::RangePatternBound> lower (
10319 new AST::RangePatternBoundLiteral (
10320 AST::Literal (range_lower->get_str (), type,
10321 PrimitiveCoreType::CORETYPE_UNKNOWN),
10322 range_lower->get_locus (), has_minus));
10323
10324 std::unique_ptr<AST::RangePatternBound> upper
10325 = parse_range_pattern_bound ();
10326 if (upper == nullptr)
10327 {
10328 Error error (next->get_locus (),
10329 "failed to parse range pattern bound in range pattern");
10330 add_error (std::move (error));
10331
10332 return nullptr;
10333 }
10334
10335 return std::unique_ptr<AST::RangePattern> (
10336 new AST::RangePattern (std::move (lower), std::move (upper),
10337 range_lower->get_locus ()));
10338 }
10339 else
10340 {
10341 // literal pattern
10342 return std::unique_ptr<AST::LiteralPattern> (
10343 new AST::LiteralPattern (range_lower->get_str (), type,
10344 range_lower->get_locus ()));
10345 }
10346}
10347
10348// Parses a range pattern bound (value only).
10349template <typename ManagedTokenSource>
10350std::unique_ptr<AST::RangePatternBound>
10351Parser<ManagedTokenSource>::parse_range_pattern_bound ()
10352{
10353 const_TokenPtr range_lower = lexer.peek_token ();
10354 Location range_lower_locus = range_lower->get_locus ();
10355
10356 // get lit type
10357 switch (range_lower->get_id ())
10358 {
10359 case CHAR_LITERAL:
10360 lexer.skip_token ();
10361 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10362 new AST::RangePatternBoundLiteral (
10363 AST::Literal (range_lower->get_str (), AST::Literal::CHAR,
10364 range_lower->get_type_hint ()),
10365 range_lower_locus));
10366 case BYTE_CHAR_LITERAL:
10367 lexer.skip_token ();
10368 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10369 new AST::RangePatternBoundLiteral (
10370 AST::Literal (range_lower->get_str (), AST::Literal::BYTE,
10371 range_lower->get_type_hint ()),
10372 range_lower_locus));
10373 case INT_LITERAL:
10374 lexer.skip_token ();
10375 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10376 new AST::RangePatternBoundLiteral (
10377 AST::Literal (range_lower->get_str (), AST::Literal::INT,
10378 range_lower->get_type_hint ()),
10379 range_lower_locus));
10380 case FLOAT_LITERAL:
10381 lexer.skip_token ();
10382 rust_debug ("warning: used deprecated float range pattern bound");
10383 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10384 new AST::RangePatternBoundLiteral (
10385 AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
10386 range_lower->get_type_hint ()),
10387 range_lower_locus));
10388 case MINUS:
10389 // branch on next token
10390 range_lower = lexer.peek_token (1);
10391 switch (range_lower->get_id ())
10392 {
10393 case INT_LITERAL:
10394 lexer.skip_token (1);
10395 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10396 new AST::RangePatternBoundLiteral (
10397 AST::Literal (range_lower->get_str (), AST::Literal::INT,
10398 range_lower->get_type_hint ()),
10399 range_lower_locus, true));
10400 case FLOAT_LITERAL:
10401 lexer.skip_token (1);
10402 rust_debug ("warning: used deprecated float range pattern bound");
10403 return std::unique_ptr<AST::RangePatternBoundLiteral> (
10404 new AST::RangePatternBoundLiteral (
10405 AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
10406 range_lower->get_type_hint ()),
10407 range_lower_locus, true));
10408 default:
10409 add_error (Error (range_lower->get_locus (),
10410 "token type %qs cannot be parsed as range pattern "
10411 "bound after minus symbol",
10412 range_lower->get_token_description ()));
10413
10414 return nullptr;
10415 }
10416 case IDENTIFIER:
10417 case SUPER:
10418 case SELF:
10419 case SELF_ALIAS:
10420 case CRATE:
10421 case SCOPE_RESOLUTION:
10422 case DOLLAR_SIGN: {
10423 // path in expression
10424 AST::PathInExpression path = parse_path_in_expression ();
10425 if (path.is_error ())
10426 {
10427 Error error (
10428 range_lower->get_locus (),
10429 "failed to parse path in expression range pattern bound");
10430 add_error (std::move (error));
10431
10432 return nullptr;
10433 }
10434 return std::unique_ptr<AST::RangePatternBoundPath> (
10435 new AST::RangePatternBoundPath (std::move (path)));
10436 }
10437 case LEFT_ANGLE: {
10438 // qualified path in expression
10439 AST::QualifiedPathInExpression path
10440 = parse_qualified_path_in_expression ();
10441 if (path.is_error ())
10442 {
10443 Error error (range_lower->get_locus (),
10444 "failed to parse qualified path in expression range "
10445 "pattern bound");
10446 add_error (std::move (error));
10447
10448 return nullptr;
10449 }
10450 return std::unique_ptr<AST::RangePatternBoundQualPath> (
10451 new AST::RangePatternBoundQualPath (std::move (path)));
10452 }
10453 default:
10454 add_error (
10455 Error (range_lower->get_locus (),
10456 "token type %qs cannot be parsed as range pattern bound",
10457 range_lower->get_token_description ()));
10458
10459 return nullptr;
10460 }
10461}
10462
10463// Parses a pattern (will further disambiguate any pattern).
10464template <typename ManagedTokenSource>
10465std::unique_ptr<AST::Pattern>
10466Parser<ManagedTokenSource>::parse_pattern ()
10467{
10468 const_TokenPtr t = lexer.peek_token ();
10469 switch (t->get_id ())
10470 {
10471 case TRUE_LITERAL:
10472 lexer.skip_token ();
10473 return std::unique_ptr<AST::LiteralPattern> (
10474 new AST::LiteralPattern ("true", AST::Literal::BOOL, t->get_locus ()));
10475 case FALSE_LITERAL:
10476 lexer.skip_token ();
10477 return std::unique_ptr<AST::LiteralPattern> (
10478 new AST::LiteralPattern ("false", AST::Literal::BOOL, t->get_locus ()));
10479 case CHAR_LITERAL:
10480 case BYTE_CHAR_LITERAL:
10481 case INT_LITERAL:
10482 case FLOAT_LITERAL:
10483 return parse_literal_or_range_pattern ();
10484 case STRING_LITERAL:
10485 lexer.skip_token ();
10486 return std::unique_ptr<AST::LiteralPattern> (
10487 new AST::LiteralPattern (t->get_str (), AST::Literal::STRING,
10488 t->get_locus ()));
10489 case BYTE_STRING_LITERAL:
10490 lexer.skip_token ();
10491 return std::unique_ptr<AST::LiteralPattern> (
10492 new AST::LiteralPattern (t->get_str (), AST::Literal::BYTE_STRING,
10493 t->get_locus ()));
10494 // raw string and raw byte string literals too if they are readded to
10495 // lexer
10496 case MINUS:
10497 if (lexer.peek_token (1)->get_id () == INT_LITERAL)
10498 {
10499 return parse_literal_or_range_pattern ();
10500 }
10501 else if (lexer.peek_token (1)->get_id () == FLOAT_LITERAL)
10502 {
10503 return parse_literal_or_range_pattern ();
10504 }
10505 else
10506 {
10507 Error error (t->get_locus (), "unexpected token %<-%> in pattern - "
10508 "did you forget an integer literal");
10509 add_error (std::move (error));
10510
10511 return nullptr;
10512 }
10513 case UNDERSCORE:
10514 lexer.skip_token ();
10515 return std::unique_ptr<AST::WildcardPattern> (
10516 new AST::WildcardPattern (t->get_locus ()));
10517 case REF:
10518 case MUT:
10519 return parse_identifier_pattern ();
10520 case IDENTIFIER:
10521 /* if identifier with no scope resolution afterwards, identifier
10522 * pattern. if scope resolution afterwards, path pattern (or range
10523 * pattern or struct pattern or tuple struct pattern) or macro
10524 * invocation */
10525 return parse_ident_leading_pattern ();
10526 case AMP:
10527 case LOGICAL_AND:
10528 // reference pattern
10529 return parse_reference_pattern ();
10530 case LEFT_PAREN:
10531 // tuple pattern or grouped pattern
10532 return parse_grouped_or_tuple_pattern ();
10533 case LEFT_SQUARE:
10534 // slice pattern
10535 return parse_slice_pattern ();
10536 case LEFT_ANGLE: {
10537 // qualified path in expression or qualified range pattern bound
10538 AST::QualifiedPathInExpression path
10539 = parse_qualified_path_in_expression ();
10540
10541 if (lexer.peek_token ()->get_id () == DOT_DOT_EQ
10542 || lexer.peek_token ()->get_id () == ELLIPSIS)
10543 {
10544 // qualified range pattern bound, so parse rest of range pattern
10545 bool has_ellipsis_syntax
10546 = lexer.peek_token ()->get_id () == ELLIPSIS;
10547 lexer.skip_token ();
10548
10549 std::unique_ptr<AST::RangePatternBoundQualPath> lower_bound (
10550 new AST::RangePatternBoundQualPath (std::move (path)));
10551 std::unique_ptr<AST::RangePatternBound> upper_bound
10552 = parse_range_pattern_bound ();
10553
10554 return std::unique_ptr<AST::RangePattern> (
10555 new AST::RangePattern (std::move (lower_bound),
10556 std::move (upper_bound), t->get_locus (),
10557 has_ellipsis_syntax));
10558 }
10559 else
10560 {
10561 // just qualified path in expression
10562 return std::unique_ptr<AST::QualifiedPathInExpression> (
10563 new AST::QualifiedPathInExpression (std::move (path)));
10564 }
10565 }
10566 case SUPER:
10567 case SELF:
10568 case SELF_ALIAS:
10569 case CRATE:
10570 case SCOPE_RESOLUTION:
10571 case DOLLAR_SIGN: {
10572 // path in expression or range pattern bound
10573 AST::PathInExpression path = parse_path_in_expression ();
10574
10575 const_TokenPtr next = lexer.peek_token ();
10576 switch (next->get_id ())
10577 {
10578 case DOT_DOT_EQ:
10579 case ELLIPSIS: {
10580 // qualified range pattern bound, so parse rest of range pattern
10581 bool has_ellipsis_syntax
10582 = lexer.peek_token ()->get_id () == ELLIPSIS;
10583 lexer.skip_token ();
10584
10585 std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
10586 new AST::RangePatternBoundPath (std::move (path)));
10587 std::unique_ptr<AST::RangePatternBound> upper_bound
10588 = parse_range_pattern_bound ();
10589
10590 return std::unique_ptr<AST::RangePattern> (new AST::RangePattern (
10591 std::move (lower_bound), std::move (upper_bound),
10592 Linemap::unknown_location (), has_ellipsis_syntax));
10593 }
10594 case EXCLAM:
10595 return parse_macro_invocation_partial (std::move (path),
10596 AST::AttrVec ());
10597 case LEFT_PAREN: {
10598 // tuple struct
10599 lexer.skip_token ();
10600
10601 // check if empty tuple
10602 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
10603 {
10604 lexer.skip_token ();
10605 return std::unique_ptr<AST::TupleStructPattern> (
10606 new AST::TupleStructPattern (std::move (path), nullptr));
10607 }
10608
10609 // parse items
10610 std::unique_ptr<AST::TupleStructItems> items
10611 = parse_tuple_struct_items ();
10612 if (items == nullptr)
10613 {
10614 Error error (lexer.peek_token ()->get_locus (),
10615 "failed to parse tuple struct items");
10616 add_error (std::move (error));
10617
10618 return nullptr;
10619 }
10620
10621 if (!skip_token (RIGHT_PAREN))
10622 {
10623 return nullptr;
10624 }
10625
10626 return std::unique_ptr<AST::TupleStructPattern> (
10627 new AST::TupleStructPattern (std::move (path),
10628 std::move (items)));
10629 }
10630 case LEFT_CURLY: {
10631 // struct
10632 lexer.skip_token ();
10633
10634 // parse elements (optional)
10635 AST::StructPatternElements elems = parse_struct_pattern_elems ();
10636
10637 if (!skip_token (RIGHT_CURLY))
10638 {
10639 return nullptr;
10640 }
10641
10642 return std::unique_ptr<AST::StructPattern> (
10643 new AST::StructPattern (std::move (path), t->get_locus (),
10644 std::move (elems)));
10645 }
10646 default:
10647 // assume path in expression
10648 return std::unique_ptr<AST::PathInExpression> (
10649 new AST::PathInExpression (std::move (path)));
10650 }
10651 }
10652 default:
10653 add_error (Error (t->get_locus (), "unexpected token %qs in pattern",
10654 t->get_token_description ()));
10655
10656 return nullptr;
10657 }
10658}
10659
10660// Parses a single or double reference pattern.
10661template <typename ManagedTokenSource>
10662std::unique_ptr<AST::ReferencePattern>
10663Parser<ManagedTokenSource>::parse_reference_pattern ()
10664{
10665 // parse double or single ref
10666 bool is_double_ref = false;
10667 const_TokenPtr t = lexer.peek_token ();
10668 switch (t->get_id ())
10669 {
10670 case AMP:
10671 // still false
10672 lexer.skip_token ();
10673 break;
10674 case LOGICAL_AND:
10675 is_double_ref = true;
10676 lexer.skip_token ();
10677 break;
10678 default:
10679 add_error (Error (t->get_locus (),
10680 "unexpected token %qs in reference pattern",
10681 t->get_token_description ()));
10682
10683 return nullptr;
10684 }
10685
10686 // parse mut (if it exists)
10687 bool is_mut = false;
10688 if (lexer.peek_token ()->get_id () == MUT)
10689 {
10690 is_mut = true;
10691 lexer.skip_token ();
10692 }
10693
10694 // parse pattern to get reference of (required)
10695 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10696 if (pattern == nullptr)
10697 {
10698 Error error (lexer.peek_token ()->get_locus (),
10699 "failed to parse pattern in reference pattern");
10700 add_error (std::move (error));
10701
10702 // skip somewhere?
10703 return nullptr;
10704 }
10705
10706 return std::unique_ptr<AST::ReferencePattern> (
10707 new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref,
10708 t->get_locus ()));
10709}
10710
10711/* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if
10712 * only a single element with no commas. */
10713template <typename ManagedTokenSource>
10714std::unique_ptr<AST::Pattern>
10715Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern ()
10716{
10717 Location paren_locus = lexer.peek_token ()->get_locus ();
10718 skip_token (LEFT_PAREN);
10719
10720 // detect '..' token (ranged with no lower range)
10721 if (lexer.peek_token ()->get_id () == DOT_DOT)
10722 {
10723 lexer.skip_token ();
10724
10725 // parse new patterns while next token is a comma
10726 std::vector<std::unique_ptr<AST::Pattern>> patterns;
10727
10728 const_TokenPtr t = lexer.peek_token ();
10729 while (t->get_id () == COMMA)
10730 {
10731 lexer.skip_token ();
10732
10733 // break if next token is ')'
10734 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
10735 {
10736 break;
10737 }
10738
10739 // parse pattern, which is required
10740 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10741 if (pattern == nullptr)
10742 {
10743 Error error (
10744 lexer.peek_token ()->get_locus (),
10745 "failed to parse pattern inside ranged tuple pattern");
10746 add_error (std::move (error));
10747
10748 // skip somewhere?
10749 return nullptr;
10750 }
10751 patterns.push_back (std::move (pattern));
10752
10753 t = lexer.peek_token ();
10754 }
10755
10756 if (!skip_token (RIGHT_PAREN))
10757 {
10758 // skip somewhere?
10759 return nullptr;
10760 }
10761
10762 // create ranged tuple pattern items with only upper items
10763 std::unique_ptr<AST::TuplePatternItemsRanged> items (
10764 new AST::TuplePatternItemsRanged (
10765 std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns)));
10766 return std::unique_ptr<AST::TuplePattern> (
10767 new AST::TuplePattern (std::move (items), paren_locus));
10768 }
10769
10770 // parse initial pattern (required)
10771 std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
10772 if (initial_pattern == nullptr)
10773 {
10774 Error error (lexer.peek_token ()->get_locus (),
10775 "failed to parse pattern in grouped or tuple pattern");
10776 add_error (std::move (error));
10777
10778 return nullptr;
10779 }
10780
10781 // branch on whether next token is a comma or not
10782 const_TokenPtr t = lexer.peek_token ();
10783 switch (t->get_id ())
10784 {
10785 case RIGHT_PAREN:
10786 // grouped pattern
10787 lexer.skip_token ();
10788
10789 return std::unique_ptr<AST::GroupedPattern> (
10790 new AST::GroupedPattern (std::move (initial_pattern), paren_locus));
10791 case COMMA: {
10792 // tuple pattern
10793 lexer.skip_token ();
10794
10795 // create vector of patterns
10796 std::vector<std::unique_ptr<AST::Pattern>> patterns;
10797 patterns.push_back (std::move (initial_pattern));
10798
10799 t = lexer.peek_token ();
10800 while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
10801 {
10802 // parse pattern (required)
10803 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10804 if (pattern == nullptr)
10805 {
10806 Error error (t->get_locus (),
10807 "failed to parse pattern in tuple pattern");
10808 add_error (std::move (error));
10809
10810 return nullptr;
10811 }
10812 patterns.push_back (std::move (pattern));
10813
10814 if (lexer.peek_token ()->get_id () != COMMA)
10815 break;
10816
10817 lexer.skip_token ();
10818 t = lexer.peek_token ();
10819 }
10820
10821 t = lexer.peek_token ();
10822 if (t->get_id () == RIGHT_PAREN)
10823 {
10824 // non-ranged tuple pattern
10825 lexer.skip_token ();
10826
10827 std::unique_ptr<AST::TuplePatternItemsMultiple> items (
10828 new AST::TuplePatternItemsMultiple (std::move (patterns)));
10829 return std::unique_ptr<AST::TuplePattern> (
10830 new AST::TuplePattern (std::move (items), paren_locus));
10831 }
10832 else if (t->get_id () == DOT_DOT)
10833 {
10834 // ranged tuple pattern
10835 lexer.skip_token ();
10836
10837 // parse upper patterns
10838 std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
10839 t = lexer.peek_token ();
10840 while (t->get_id () == COMMA)
10841 {
10842 lexer.skip_token ();
10843
10844 // break if end
10845 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
10846 break;
10847
10848 // parse pattern (required)
10849 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10850 if (pattern == nullptr)
10851 {
10852 Error error (lexer.peek_token ()->get_locus (),
10853 "failed to parse pattern in tuple pattern");
10854 add_error (std::move (error));
10855
10856 return nullptr;
10857 }
10858 upper_patterns.push_back (std::move (pattern));
10859
10860 t = lexer.peek_token ();
10861 }
10862
10863 if (!skip_token (RIGHT_PAREN))
10864 {
10865 return nullptr;
10866 }
10867
10868 std::unique_ptr<AST::TuplePatternItemsRanged> items (
10869 new AST::TuplePatternItemsRanged (std::move (patterns),
10870 std::move (upper_patterns)));
10871 return std::unique_ptr<AST::TuplePattern> (
10872 new AST::TuplePattern (std::move (items), paren_locus));
10873 }
10874 else
10875 {
10876 // some kind of error
10877 Error error (t->get_locus (),
10878 "failed to parse tuple pattern (probably) or maybe "
10879 "grouped pattern");
10880 add_error (std::move (error));
10881
10882 return nullptr;
10883 }
10884 }
10885 default:
10886 // error
10887 add_error (Error (t->get_locus (),
10888 "unrecognised token %qs in grouped or tuple pattern "
10889 "after first pattern",
10890 t->get_token_description ()));
10891
10892 return nullptr;
10893 }
10894}
10895
10896/* Parses a slice pattern that can match arrays or slices. Parses the square
10897 * brackets too. */
10898template <typename ManagedTokenSource>
10899std::unique_ptr<AST::SlicePattern>
10900Parser<ManagedTokenSource>::parse_slice_pattern ()
10901{
10902 Location square_locus = lexer.peek_token ()->get_locus ();
10903 skip_token (LEFT_SQUARE);
10904
10905 // parse initial pattern (required)
10906 std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
10907 if (initial_pattern == nullptr)
10908 {
10909 Error error (lexer.peek_token ()->get_locus (),
10910 "failed to parse initial pattern in slice pattern");
10911 add_error (std::move (error));
10912
10913 return nullptr;
10914 }
10915
10916 std::vector<std::unique_ptr<AST::Pattern>> patterns;
10917 patterns.push_back (std::move (initial_pattern));
10918
10919 const_TokenPtr t = lexer.peek_token ();
10920 while (t->get_id () == COMMA)
10921 {
10922 lexer.skip_token ();
10923
10924 // break if end bracket
10925 if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
10926 break;
10927
10928 // parse pattern (required)
10929 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
10930 if (pattern == nullptr)
10931 {
10932 Error error (lexer.peek_token ()->get_locus (),
10933 "failed to parse pattern in slice pattern");
10934 add_error (std::move (error));
10935
10936 return nullptr;
10937 }
10938 patterns.push_back (std::move (pattern));
10939
10940 t = lexer.peek_token ();
10941 }
10942
10943 if (!skip_token (RIGHT_SQUARE))
10944 {
10945 return nullptr;
10946 }
10947
10948 return std::unique_ptr<AST::SlicePattern> (
10949 new AST::SlicePattern (std::move (patterns), square_locus));
10950}
10951
10952/* Parses an identifier pattern (pattern that binds a value matched to a
10953 * variable). */
10954template <typename ManagedTokenSource>
10955std::unique_ptr<AST::IdentifierPattern>
10956Parser<ManagedTokenSource>::parse_identifier_pattern ()
10957{
10958 Location locus = lexer.peek_token ()->get_locus ();
10959
10960 bool has_ref = false;
10961 if (lexer.peek_token ()->get_id () == REF)
10962 {
10963 has_ref = true;
10964 lexer.skip_token ();
10965
10966 // DEBUG
10967 rust_debug ("parsed ref in identifier pattern");
10968 }
10969
10970 bool has_mut = false;
10971 if (lexer.peek_token ()->get_id () == MUT)
10972 {
10973 has_mut = true;
10974 lexer.skip_token ();
10975 }
10976
10977 // parse identifier (required)
10978 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
10979 if (ident_tok == nullptr)
10980 {
10981 // skip somewhere?
10982 return nullptr;
10983 }
10984 Identifier ident = ident_tok->get_str ();
10985
10986 // DEBUG
10987 rust_debug ("parsed identifier in identifier pattern");
10988
10989 // parse optional pattern binding thing
10990 std::unique_ptr<AST::Pattern> bind_pattern = nullptr;
10991 if (lexer.peek_token ()->get_id () == PATTERN_BIND)
10992 {
10993 lexer.skip_token ();
10994
10995 // parse required pattern to bind
10996 bind_pattern = parse_pattern ();
10997 if (bind_pattern == nullptr)
10998 {
10999 Error error (lexer.peek_token ()->get_locus (),
11000 "failed to parse pattern to bind in identifier pattern");
11001 add_error (std::move (error));
11002
11003 return nullptr;
11004 }
11005 }
11006
11007 // DEBUG
11008 rust_debug ("about to return identifier pattern");
11009
11010 return std::unique_ptr<AST::IdentifierPattern> (
11011 new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut,
11012 std::move (bind_pattern)));
11013}
11014
11015/* Parses a pattern that opens with an identifier. This includes identifier
11016 * patterns, path patterns (and derivatives such as struct patterns, tuple
11017 * struct patterns, and macro invocations), and ranges. */
11018template <typename ManagedTokenSource>
11019std::unique_ptr<AST::Pattern>
11020Parser<ManagedTokenSource>::parse_ident_leading_pattern ()
11021{
11022 // ensure first token is actually identifier
11023 const_TokenPtr initial_tok = lexer.peek_token ();
11024 if (initial_tok->get_id () != IDENTIFIER)
11025 {
11026 return nullptr;
11027 }
11028
11029 // save initial identifier as it may be useful (but don't skip)
11030 std::string initial_ident = initial_tok->get_str ();
11031
11032 // parse next tokens as a PathInExpression
11033 AST::PathInExpression path = parse_path_in_expression ();
11034
11035 // branch on next token
11036 const_TokenPtr t = lexer.peek_token ();
11037 switch (t->get_id ())
11038 {
11039 case EXCLAM:
11040 return parse_macro_invocation_partial (std::move (path), AST::AttrVec ());
11041 case LEFT_PAREN: {
11042 // tuple struct
11043 lexer.skip_token ();
11044
11045 // DEBUG
11046 rust_debug ("parsing tuple struct pattern");
11047
11048 // check if empty tuple
11049 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
11050 {
11051 lexer.skip_token ();
11052 return std::unique_ptr<AST::TupleStructPattern> (
11053 new AST::TupleStructPattern (std::move (path), nullptr));
11054 }
11055
11056 // parse items
11057 std::unique_ptr<AST::TupleStructItems> items
11058 = parse_tuple_struct_items ();
11059 if (items == nullptr)
11060 {
11061 Error error (lexer.peek_token ()->get_locus (),
11062 "failed to parse tuple struct items");
11063 add_error (std::move (error));
11064
11065 return nullptr;
11066 }
11067
11068 // DEBUG
11069 rust_debug ("successfully parsed tuple struct items");
11070
11071 if (!skip_token (RIGHT_PAREN))
11072 {
11073 return nullptr;
11074 }
11075
11076 // DEBUG
11077 rust_debug ("successfully parsed tuple struct pattern");
11078
11079 return std::unique_ptr<AST::TupleStructPattern> (
11080 new AST::TupleStructPattern (std::move (path), std::move (items)));
11081 }
11082 case LEFT_CURLY: {
11083 // struct
11084 lexer.skip_token ();
11085
11086 // parse elements (optional)
11087 AST::StructPatternElements elems = parse_struct_pattern_elems ();
11088
11089 if (!skip_token (RIGHT_CURLY))
11090 {
11091 return nullptr;
11092 }
11093
11094 // DEBUG
11095 rust_debug ("successfully parsed struct pattern");
11096
11097 return std::unique_ptr<AST::StructPattern> (
11098 new AST::StructPattern (std::move (path), initial_tok->get_locus (),
11099 std::move (elems)));
11100 }
11101 case DOT_DOT_EQ:
11102 case ELLIPSIS: {
11103 // range
11104 bool has_ellipsis_syntax = lexer.peek_token ()->get_id () == ELLIPSIS;
11105
11106 lexer.skip_token ();
11107
11108 std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
11109 new AST::RangePatternBoundPath (std::move (path)));
11110 std::unique_ptr<AST::RangePatternBound> upper_bound
11111 = parse_range_pattern_bound ();
11112
11113 return std::unique_ptr<AST::RangePattern> (new AST::RangePattern (
11114 std::move (lower_bound), std::move (upper_bound),
11115 Linemap::unknown_location (), has_ellipsis_syntax));
11116 }
11117 case PATTERN_BIND: {
11118 // only allow on single-segment paths
11119 if (path.is_single_segment ())
11120 {
11121 // identifier with pattern bind
11122 lexer.skip_token ();
11123
11124 std::unique_ptr<AST::Pattern> bind_pattern = parse_pattern ();
11125 if (bind_pattern == nullptr)
11126 {
11127 Error error (
11128 t->get_locus (),
11129 "failed to parse pattern to bind to identifier pattern");
11130 add_error (std::move (error));
11131
11132 return nullptr;
11133 }
11134 return std::unique_ptr<AST::IdentifierPattern> (
11135 new AST::IdentifierPattern (std::move (initial_ident),
11136 initial_tok->get_locus (), false,
11137 false, std::move (bind_pattern)));
11138 }
11139 Error error (
11140 t->get_locus (),
11141 "failed to parse pattern bind to a path, not an identifier");
11142 add_error (std::move (error));
11143
11144 return nullptr;
11145 }
11146 default:
11147 // assume identifier if single segment
11148 if (path.is_single_segment ())
11149 {
11150 return std::unique_ptr<AST::IdentifierPattern> (
11151 new AST::IdentifierPattern (std::move (initial_ident),
11152 initial_tok->get_locus ()));
11153 }
11154 // return path otherwise
11155 return std::unique_ptr<AST::PathInExpression> (
11156 new AST::PathInExpression (std::move (path)));
11157 }
11158}
11159
11160// Parses tuple struct items if they exist. Does not parse parentheses.
11161template <typename ManagedTokenSource>
11162std::unique_ptr<AST::TupleStructItems>
11163Parser<ManagedTokenSource>::parse_tuple_struct_items ()
11164{
11165 std::vector<std::unique_ptr<AST::Pattern>> lower_patterns;
11166
11167 // DEBUG
11168 rust_debug ("started parsing tuple struct items");
11169
11170 // check for '..' at front
11171 if (lexer.peek_token ()->get_id () == DOT_DOT)
11172 {
11173 // only parse upper patterns
11174 lexer.skip_token ();
11175
11176 // DEBUG
11177 rust_debug ("'..' at front in tuple struct items detected");
11178
11179 std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
11180
11181 const_TokenPtr t = lexer.peek_token ();
11182 while (t->get_id () == COMMA)
11183 {
11184 lexer.skip_token ();
11185
11186 // break if right paren
11187 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
11188 break;
11189
11190 // parse pattern, which is now required
11191 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11192 if (pattern == nullptr)
11193 {
11194 Error error (lexer.peek_token ()->get_locus (),
11195 "failed to parse pattern in tuple struct items");
11196 add_error (std::move (error));
11197
11198 return nullptr;
11199 }
11200 upper_patterns.push_back (std::move (pattern));
11201
11202 t = lexer.peek_token ();
11203 }
11204
11205 // DEBUG
11206 rust_debug (
11207 "finished parsing tuple struct items ranged (upper/none only)");
11208
11209 return std::unique_ptr<AST::TupleStructItemsRange> (
11210 new AST::TupleStructItemsRange (std::move (lower_patterns),
11211 std::move (upper_patterns)));
11212 }
11213
11214 // has at least some lower patterns
11215 const_TokenPtr t = lexer.peek_token ();
11216 while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
11217 {
11218 // DEBUG
11219 rust_debug ("about to parse pattern in tuple struct items");
11220
11221 // parse pattern, which is required
11222 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11223 if (pattern == nullptr)
11224 {
11225 Error error (t->get_locus (),
11226 "failed to parse pattern in tuple struct items");
11227 add_error (std::move (error));
11228
11229 return nullptr;
11230 }
11231 lower_patterns.push_back (std::move (pattern));
11232
11233 // DEBUG
11234 rust_debug ("successfully parsed pattern in tuple struct items");
11235
11236 if (lexer.peek_token ()->get_id () != COMMA)
11237 {
11238 // DEBUG
11239 rust_debug ("broke out of parsing patterns in tuple struct "
11240 "items as no comma");
11241
11242 break;
11243 }
11244 lexer.skip_token ();
11245 t = lexer.peek_token ();
11246 }
11247
11248 // branch on next token
11249 t = lexer.peek_token ();
11250 switch (t->get_id ())
11251 {
11252 case RIGHT_PAREN:
11253 return std::unique_ptr<AST::TupleStructItemsNoRange> (
11254 new AST::TupleStructItemsNoRange (std::move (lower_patterns)));
11255 case DOT_DOT: {
11256 // has an upper range that must be parsed separately
11257 lexer.skip_token ();
11258
11259 std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
11260
11261 t = lexer.peek_token ();
11262 while (t->get_id () == COMMA)
11263 {
11264 lexer.skip_token ();
11265
11266 // break if next token is right paren
11267 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
11268 break;
11269
11270 // parse pattern, which is required
11271 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11272 if (pattern == nullptr)
11273 {
11274 Error error (lexer.peek_token ()->get_locus (),
11275 "failed to parse pattern in tuple struct items");
11276 add_error (std::move (error));
11277
11278 return nullptr;
11279 }
11280 upper_patterns.push_back (std::move (pattern));
11281
11282 t = lexer.peek_token ();
11283 }
11284
11285 return std::unique_ptr<AST::TupleStructItemsRange> (
11286 new AST::TupleStructItemsRange (std::move (lower_patterns),
11287 std::move (upper_patterns)));
11288 }
11289 default:
11290 // error
11291 add_error (Error (t->get_locus (),
11292 "unexpected token %qs in tuple struct items",
11293 t->get_token_description ()));
11294
11295 return nullptr;
11296 }
11297}
11298
11299// Parses struct pattern elements if they exist.
11300template <typename ManagedTokenSource>
11301AST::StructPatternElements
11302Parser<ManagedTokenSource>::parse_struct_pattern_elems ()
11303{
11304 std::vector<std::unique_ptr<AST::StructPatternField>> fields;
11305
11306 AST::AttrVec etc_attrs;
11307 bool has_etc = false;
11308
11309 // try parsing struct pattern fields
11310 const_TokenPtr t = lexer.peek_token ();
11311 while (t->get_id () != RIGHT_CURLY)
11312 {
11313 AST::AttrVec outer_attrs = parse_outer_attributes ();
11314
11315 // parse etc (must be last in struct pattern, so breaks)
11316 if (lexer.peek_token ()->get_id () == DOT_DOT)
11317 {
11318 lexer.skip_token ();
11319 etc_attrs = std::move (outer_attrs);
11320 has_etc = true;
11321 break;
11322 }
11323
11324 std::unique_ptr<AST::StructPatternField> field
11325 = parse_struct_pattern_field_partial (std::move (outer_attrs));
11326 if (field == nullptr)
11327 {
11328 Error error (lexer.peek_token ()->get_locus (),
11329 "failed to parse struct pattern field");
11330 add_error (std::move (error));
11331
11332 // skip after somewhere?
11333 return AST::StructPatternElements::create_empty ();
11334 }
11335 fields.push_back (std::move (field));
11336
11337 if (lexer.peek_token ()->get_id () != COMMA)
11338 break;
11339
11340 // skip comma
11341 lexer.skip_token ();
11342 t = lexer.peek_token ();
11343 }
11344
11345 if (has_etc)
11346 return AST::StructPatternElements (std::move (fields),
11347 std::move (etc_attrs));
11348 else
11349 return AST::StructPatternElements (std::move (fields));
11350}
11351
11352/* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
11353 * identifier). */
11354template <typename ManagedTokenSource>
11355std::unique_ptr<AST::StructPatternField>
11356Parser<ManagedTokenSource>::parse_struct_pattern_field ()
11357{
11358 // parse outer attributes (if they exist)
11359 AST::AttrVec outer_attrs = parse_outer_attributes ();
11360
11361 return parse_struct_pattern_field_partial (std::move (outer_attrs));
11362}
11363
11364/* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
11365 * identifier), with outer attributes passed in. */
11366template <typename ManagedTokenSource>
11367std::unique_ptr<AST::StructPatternField>
11368Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
11369 AST::AttrVec outer_attrs)
11370{
11371 // branch based on next token
11372 const_TokenPtr t = lexer.peek_token ();
11373 switch (t->get_id ())
11374 {
11375 case INT_LITERAL: {
11376 // tuple index
11377 std::string index_str = t->get_str ();
11378 int index = atoi (index_str.c_str ());
11379
11380 if (!skip_token (COLON))
11381 {
11382 return nullptr;
11383 }
11384
11385 // parse required pattern
11386 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11387 if (pattern == nullptr)
11388 {
11389 Error error (
11390 t->get_locus (),
11391 "failed to parse pattern in tuple index struct pattern field");
11392 add_error (std::move (error));
11393
11394 return nullptr;
11395 }
11396
11397 return std::unique_ptr<AST::StructPatternFieldTuplePat> (
11398 new AST::StructPatternFieldTuplePat (index, std::move (pattern),
11399 std::move (outer_attrs),
11400 t->get_locus ()));
11401 }
11402 case IDENTIFIER:
11403 // identifier-pattern OR only identifier
11404 // branch on next token
11405 switch (lexer.peek_token (1)->get_id ())
11406 {
11407 case COLON: {
11408 // identifier-pattern
11409 Identifier ident = t->get_str ();
11410 lexer.skip_token ();
11411
11412 skip_token (COLON);
11413
11414 // parse required pattern
11415 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
11416 if (pattern == nullptr)
11417 {
11418 Error error (t->get_locus (),
11419 "failed to parse pattern in struct pattern field");
11420 add_error (std::move (error));
11421
11422 return nullptr;
11423 }
11424
11425 return std::unique_ptr<AST::StructPatternFieldIdentPat> (
11426 new AST::StructPatternFieldIdentPat (std::move (ident),
11427 std::move (pattern),
11428 std::move (outer_attrs),
11429 t->get_locus ()));
11430 }
11431 case COMMA:
11432 case RIGHT_CURLY: {
11433 // identifier only
11434 Identifier ident = t->get_str ();
11435 lexer.skip_token ();
11436
11437 return std::unique_ptr<AST::StructPatternFieldIdent> (
11438 new AST::StructPatternFieldIdent (std::move (ident), false, false,
11439 std::move (outer_attrs),
11440 t->get_locus ()));
11441 }
11442 default:
11443 // error
11444 add_error (Error (t->get_locus (),
11445 "unrecognised token %qs in struct pattern field",
11446 t->get_token_description ()));
11447
11448 return nullptr;
11449 }
11450 case REF:
11451 case MUT: {
11452 // only identifier
11453 bool has_ref = false;
11454 if (t->get_id () == REF)
11455 {
11456 has_ref = true;
11457 lexer.skip_token ();
11458 }
11459
11460 bool has_mut = false;
11461 if (lexer.peek_token ()->get_id () == MUT)
11462 {
11463 has_mut = true;
11464 lexer.skip_token ();
11465 }
11466
11467 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
11468 if (ident_tok == nullptr)
11469 {
11470 return nullptr;
11471 }
11472 Identifier ident = ident_tok->get_str ();
11473
11474 return std::unique_ptr<AST::StructPatternFieldIdent> (
11475 new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut,
11476 std::move (outer_attrs),
11477 t->get_locus ()));
11478 }
11479 default:
11480 // not necessarily an error
11481 return nullptr;
11482 }
11483}
11484
11485template <typename ManagedTokenSource>
11486ExprOrStmt
11487Parser<ManagedTokenSource>::parse_stmt_or_expr_with_block (
11488 AST::AttrVec outer_attrs)
11489{
11490 auto expr = parse_expr_with_block (std::move (outer_attrs));
11491 if (expr == nullptr)
11492 return ExprOrStmt::create_error ();
11493
11494 auto tok = lexer.peek_token ();
11495
11496 // tail expr in a block expr
11497 if (tok->get_id () == RIGHT_CURLY)
11498 return ExprOrStmt (std::move (expr));
11499
11500 // internal block expr must either have semicolons followed, or evaluate to
11501 // ()
11502 auto locus = expr->get_locus ();
11503 std::unique_ptr<AST::ExprStmtWithBlock> stmt (
11504 new AST::ExprStmtWithBlock (std::move (expr), locus,
11505 tok->get_id () == SEMICOLON));
11506 if (tok->get_id () == SEMICOLON)
11507 lexer.skip_token ();
11508
11509 return ExprOrStmt (std::move (stmt));
11510}
11511
11512/* Parses a statement or expression (depending on whether a trailing semicolon
11513 * exists). Useful for block expressions where it cannot be determined through
11514 * lookahead whether it is a statement or expression to be parsed. */
11515template <typename ManagedTokenSource>
11516ExprOrStmt
11517Parser<ManagedTokenSource>::parse_stmt_or_expr_without_block ()
11518{
11519 // quick exit for empty statement
11520 const_TokenPtr t = lexer.peek_token ();
11521 if (t->get_id () == SEMICOLON)
11522 {
11523 lexer.skip_token ();
11524 std::unique_ptr<AST::EmptyStmt> stmt (
11525 new AST::EmptyStmt (t->get_locus ()));
11526 return ExprOrStmt (std::move (stmt));
11527 }
11528
11529 // parse outer attributes
11530 AST::AttrVec outer_attrs = parse_outer_attributes ();
11531
11532 // parsing this will be annoying because of the many different possibilities
11533 /* best may be just to copy paste in parse_item switch, and failing that try
11534 * to parse outer attributes, and then pass them in to either a let
11535 * statement or (fallback) expression statement. */
11536 // FIXME: think of a way to do this without such a large switch?
11537
11538 /* FIXME: for expressions at least, the only way that they can really be
11539 * parsed properly in this way is if they don't support operators on them.
11540 * They must be pratt-parsed otherwise. As such due to composability, only
11541 * explicit statements will have special cases here. This should roughly
11542 * correspond to "expr-with-block", but this warning is here in case it
11543 * isn't the case. */
11544 t = lexer.peek_token ();
11545 switch (t->get_id ())
11546 {
11547 case LET: {
11548 // let statement
11549 std::unique_ptr<AST::LetStmt> stmt (
11550 parse_let_stmt (std::move (outer_attrs)));
11551 return ExprOrStmt (std::move (stmt));
11552 }
11553 case PUB:
11554 case MOD:
11555 case EXTERN_TOK:
11556 case USE:
11557 case FN_TOK:
11558 case TYPE:
11559 case STRUCT_TOK:
11560 case ENUM_TOK:
11561 case CONST:
11562 case STATIC_TOK:
11563 case TRAIT:
11564 case IMPL: {
11565 std::unique_ptr<AST::VisItem> item (
11566 parse_vis_item (std::move (outer_attrs)));
11567 return ExprOrStmt (std::move (item));
11568 }
11569 /* TODO: implement union keyword but not really because of
11570 * context-dependence crappy hack way to parse a union written below to
11571 * separate it from the good code. */
11572 // case UNION:
11573 case UNSAFE: { // maybe - unsafe traits are a thing
11574 /* if any of these (should be all possible VisItem prefixes), parse a
11575 * VisItem - can't parse item because would require reparsing outer
11576 * attributes */
11577 const_TokenPtr t2 = lexer.peek_token (1);
11578 switch (t2->get_id ())
11579 {
11580 case LEFT_CURLY: {
11581 // unsafe block
11582 return parse_stmt_or_expr_with_block (std::move (outer_attrs));
11583 }
11584 case TRAIT: {
11585 // unsafe trait
11586 std::unique_ptr<AST::VisItem> item (
11587 parse_vis_item (std::move (outer_attrs)));
11588 return ExprOrStmt (std::move (item));
11589 }
11590 case EXTERN_TOK:
11591 case FN_TOK: {
11592 // unsafe function
11593 std::unique_ptr<AST::VisItem> item (
11594 parse_vis_item (std::move (outer_attrs)));
11595 return ExprOrStmt (std::move (item));
11596 }
11597 case IMPL: {
11598 // unsafe trait impl
11599 std::unique_ptr<AST::VisItem> item (
11600 parse_vis_item (std::move (outer_attrs)));
11601 return ExprOrStmt (std::move (item));
11602 }
11603 default:
11604 add_error (Error (t2->get_locus (),
11605 "unrecognised token %qs after parsing unsafe - "
11606 "expected beginning of expression or statement",
11607 t->get_token_description ()));
11608
11609 // skip somewhere?
11610 return ExprOrStmt::create_error ();
11611 }
11612 }
11613 case SUPER:
11614 case SELF:
11615 case CRATE:
11616 case DOLLAR_SIGN: {
11617 /* path-based thing so struct/enum or path or macro invocation of a
11618 * kind. however, the expressions are composable (i think) */
11619
11620 std::unique_ptr<AST::ExprWithoutBlock> expr
11621 = parse_expr_without_block ();
11622
11623 if (lexer.peek_token ()->get_id () == SEMICOLON)
11624 {
11625 // must be expression statement
11626 lexer.skip_token ();
11627
11628 std::unique_ptr<AST::ExprStmtWithoutBlock> stmt (
11629 new AST::ExprStmtWithoutBlock (std::move (expr),
11630 t->get_locus ()));
11631 return ExprOrStmt (std::move (stmt));
11632 }
11633
11634 // return expression
11635 return ExprOrStmt (std::move (expr));
11636 }
11637 /* FIXME: this is either a macro invocation or macro invocation semi.
11638 * start parsing to determine which one it is. */
11639 // FIXME: or this is another path-based thing - struct/enum or path
11640 // itself return parse_path_based_stmt_or_expr(std::move(outer_attrs));
11641 // FIXME: old code there
11642 case LOOP:
11643 case WHILE:
11644 case FOR:
11645 case IF:
11646 case MATCH_TOK:
11647 case LEFT_CURLY:
11648 case ASYNC: {
11649 return parse_stmt_or_expr_with_block (std::move (outer_attrs));
11650 }
11651 case LIFETIME: {
11652 /* FIXME: are there any expressions without blocks that can have
11653 * lifetime as their first token? Or is loop expr the only one? */
11654 // safe side for now:
11655 const_TokenPtr t2 = lexer.peek_token (2);
11656 if (lexer.peek_token (1)->get_id () == COLON
11657 && (t2->get_id () == LOOP || t2->get_id () == WHILE
11658 || t2->get_id () == FOR))
11659 {
11660 return parse_stmt_or_expr_with_block (std::move (outer_attrs));
11661 }
11662 else
11663 {
11664 // should be expr without block
11665 std::unique_ptr<AST::ExprWithoutBlock> expr
11666 = parse_expr_without_block (std::move (outer_attrs));
11667
11668 if (lexer.peek_token ()->get_id () == SEMICOLON)
11669 {
11670 // must be expression statement
11671 lexer.skip_token ();
11672
11673 std::unique_ptr<AST::ExprStmtWithoutBlock> stmt (
11674 new AST::ExprStmtWithoutBlock (std::move (expr),
11675 t->get_locus ()));
11676 return ExprOrStmt (std::move (stmt));
11677 }
11678
11679 // return expression
11680 return ExprOrStmt (std::move (expr));
11681 }
11682 }
11683 // crappy hack to do union "keyword"
11684 case IDENTIFIER:
11685 if (t->get_str () == "union"
11686 && lexer.peek_token (1)->get_id () == IDENTIFIER)
11687 {
11688 std::unique_ptr<AST::VisItem> item (
11689 parse_vis_item (std::move (outer_attrs)));
11690 return ExprOrStmt (std::move (item));
11691 // or should this go straight to parsing union?
11692 }
11693 else if (t->get_str () == "macro_rules")
11694 {
11695 // macro_rules! macro item
11696 std::unique_ptr<AST::MacroItem> item (
11697 parse_macro_item (std::move (outer_attrs)));
11698 return ExprOrStmt (std::move (item));
11699 }
11700 else if (lexer.peek_token (1)->get_id () == SCOPE_RESOLUTION
11701 || lexer.peek_token (1)->get_id () == EXCLAM
11702 || lexer.peek_token (1)->get_id () == LEFT_CURLY)
11703 {
11704 /* path (probably) or macro invocation or struct or enum, so
11705 * probably a macro invocation semi decide how to parse - probably
11706 * parse path and then get macro from it */
11707
11708 // FIXME: old code was good until composability was required
11709 // return parse_path_based_stmt_or_expr(std::move(outer_attrs));
11710 std::unique_ptr<AST::ExprWithoutBlock> expr
11711 = parse_expr_without_block (std::move (outer_attrs));
11712
11713 if (lexer.peek_token ()->get_id () == SEMICOLON)
11714 {
11715 // must be expression statement
11716 lexer.skip_token ();
11717
11718 std::unique_ptr<AST::ExprStmtWithoutBlock> stmt (
11719 new AST::ExprStmtWithoutBlock (std::move (expr),
11720 t->get_locus ()));
11721 return ExprOrStmt (std::move (stmt));
11722 }
11723
11724 // return expression
11725 return ExprOrStmt (std::move (expr));
11726 }
11727 gcc_fallthrough ();
11728 // TODO: find out how to disable gcc "implicit fallthrough" warning
11729 default: {
11730 /* expression statement (without block) or expression itself - parse
11731 * expression then make it statement if semi afterwards */
11732
11733 std::unique_ptr<AST::ExprWithoutBlock> expr
11734 = parse_expr_without_block (std::move (outer_attrs));
11735
11736 if (lexer.peek_token ()->get_id () == SEMICOLON)
11737 {
11738 // must be expression statement
11739 lexer.skip_token ();
11740
11741 std::unique_ptr<AST::ExprStmtWithoutBlock> stmt (
11742 new AST::ExprStmtWithoutBlock (std::move (expr),
11743 t->get_locus ()));
11744 return ExprOrStmt (std::move (stmt));
11745 }
11746
11747 // return expression
11748 return ExprOrStmt (std::move (expr));
11749 }
11750 }
11751}
11752
11753/* Parses a statement or expression beginning with a path (i.e. macro,
11754 * struct/enum, or path expr) */
11755template <typename ManagedTokenSource>
11756ExprOrStmt
11757Parser<ManagedTokenSource>::parse_path_based_stmt_or_expr (
11758 AST::AttrVec outer_attrs)
11759{
11760 // attempt to parse path
11761 Location stmt_or_expr_loc = lexer.peek_token ()->get_locus ();
11762 AST::PathInExpression path = parse_path_in_expression ();
11763
11764 // branch on next token
11765 const_TokenPtr t2 = lexer.peek_token ();
11766 switch (t2->get_id ())
11767 {
11768 case EXCLAM: {
11769 /* macro invocation or macro invocation semi - depends on whether
11770 * there is a final ';' */
11771 // convert path in expr to simple path (as that is used in macros)
11772 AST::SimplePath macro_path = path.as_simple_path ();
11773 if (macro_path.is_empty ())
11774 {
11775 Error error (t2->get_locus (),
11776 "failed to convert parsed path to simple "
11777 "path (for macro invocation or semi)");
11778 add_error (std::move (error));
11779
11780 return ExprOrStmt::create_error ();
11781 }
11782
11783 // skip exclamation mark
11784 lexer.skip_token ();
11785
11786 const_TokenPtr t3 = lexer.peek_token ();
11787 Location tok_tree_loc = t3->get_locus ();
11788
11789 AST::DelimType type = AST::PARENS;
11790 switch (t3->get_id ())
11791 {
11792 case LEFT_PAREN:
11793 type = AST::PARENS;
11794 break;
11795 case LEFT_SQUARE:
11796 type = AST::SQUARE;
11797 break;
11798 case LEFT_CURLY:
11799 type = AST::CURLY;
11800 break;
11801 default:
11802 add_error (
11803 Error (t3->get_locus (),
11804 "unrecognised token %qs in macro invocation - (opening) "
11805 "delimiter expected",
11806 t3->get_token_description ()));
11807
11808 return ExprOrStmt::create_error ();
11809 }
11810 lexer.skip_token ();
11811
11812 // parse actual token trees
11813 std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
11814 auto delim_open
11815 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
11816 token_trees.push_back (std::move (delim_open));
11817
11818 t3 = lexer.peek_token ();
11819 // parse token trees until the initial delimiter token is found again
11820 while (!token_id_matches_delims (t3->get_id (), type))
11821 {
11822 std::unique_ptr<AST::TokenTree> tree = parse_token_tree ();
11823
11824 if (tree == nullptr)
11825 {
11826 Error error (t3->get_locus (),
11827 "failed to parse token tree for macro "
11828 "invocation (or semi) - "
11829 "found %qs",
11830 t3->get_token_description ());
11831 add_error (std::move (error));
11832
11833 return ExprOrStmt::create_error ();
11834 }
11835
11836 token_trees.push_back (std::move (tree));
11837
11838 t3 = lexer.peek_token ();
11839 }
11840
11841 auto delim_close
11842 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
11843 token_trees.push_back (std::move (delim_close));
11844
11845 // parse end delimiters
11846 t3 = lexer.peek_token ();
11847 if (token_id_matches_delims (t3->get_id (), type))
11848 {
11849 // tokens match opening delimiter, so skip.
11850 lexer.skip_token ();
11851
11852 /* with curly bracketed macros, assume it is a macro invocation
11853 * unless a semicolon is explicitly put at the end. this is not
11854 * necessarily true (i.e. context-dependence) and so may have to
11855 * be fixed up via HACKs in semantic analysis (by checking whether
11856 * it is the last elem in the vector). */
11857
11858 AST::DelimTokenTree delim_tok_tree (type, std::move (token_trees),
11859 tok_tree_loc);
11860 AST::MacroInvocData invoc_data (std::move (macro_path),
11861 std::move (delim_tok_tree));
11862
11863 if (lexer.peek_token ()->get_id () == SEMICOLON)
11864 {
11865 lexer.skip_token ();
11866
11867 std::unique_ptr<AST::MacroInvocation> stmt (
11868 new AST::MacroInvocation (std::move (invoc_data),
11869 std::move (outer_attrs),
11870 stmt_or_expr_loc, true));
11871 return ExprOrStmt (std::move (stmt));
11872 }
11873
11874 // otherwise, create macro invocation
11875 std::unique_ptr<AST::MacroInvocation> expr (
11876 new AST::MacroInvocation (std::move (invoc_data),
11877 std::move (outer_attrs),
11878 stmt_or_expr_loc, false));
11879 return ExprOrStmt (std::move (expr));
11880 }
11881 else
11882 {
11883 // tokens don't match opening delimiters, so produce error
11884 Error error (
11885 t2->get_locus (),
11886 "unexpected token %qs - expecting closing delimiter %qs (for a "
11887 "macro invocation)",
11888 t2->get_token_description (),
11889 (type == AST::PARENS ? ")" : (type == AST::SQUARE ? "]" : "}")));
11890 add_error (std::move (error));
11891
11892 return ExprOrStmt::create_error ();
11893 }
11894 }
11895 case LEFT_CURLY: {
11896 /* definitely not a block:
11897 * path '{' ident ','
11898 * path '{' ident ':' [anything] ','
11899 * path '{' ident ':' [not a type]
11900 * otherwise, assume block expr and thus path */
11901 bool not_a_block = lexer.peek_token (1)->get_id () == IDENTIFIER
11902 && (lexer.peek_token (2)->get_id () == COMMA
11903 || (lexer.peek_token (2)->get_id () == COLON
11904 && (lexer.peek_token (4)->get_id () == COMMA
11905 || !can_tok_start_type (
11906 lexer.peek_token (3)->get_id ()))));
11907 std::unique_ptr<AST::ExprWithoutBlock> expr = nullptr;
11908
11909 if (not_a_block)
11910 {
11911 /* assume struct expr struct (as struct-enum disambiguation
11912 * requires name lookup) again, make statement if final ';' */
11913 expr = parse_struct_expr_struct_partial (std::move (path),
11914 std::move (outer_attrs));
11915 if (expr == nullptr)
11916 {
11917 Error error (t2->get_locus (),
11918 "failed to parse struct expr struct");
11919 add_error (std::move (error));
11920
11921 return ExprOrStmt::create_error ();
11922 }
11923 }
11924 else
11925 {
11926 // assume path - make statement if final ';'
11927 // lexer.skip_token();
11928
11929 // HACK: add outer attrs to path
11930 path.set_outer_attrs (std::move (outer_attrs));
11931 expr = std::unique_ptr<AST::PathInExpression> (
11932 new AST::PathInExpression (std::move (path)));
11933 }
11934
11935 // determine if statement if ends with semicolon
11936 if (lexer.peek_token ()->get_id () == SEMICOLON)
11937 {
11938 // statement
11939 lexer.skip_token ();
11940 std::unique_ptr<AST::ExprStmtWithoutBlock> stmt (
11941 new AST::ExprStmtWithoutBlock (std::move (expr),
11942 stmt_or_expr_loc));
11943 return ExprOrStmt (std::move (stmt));
11944 }
11945
11946 // otherwise, expression
11947 return ExprOrStmt (std::move (expr));
11948 }
11949 case LEFT_PAREN: {
11950 /* assume struct expr tuple (as struct-enum disambiguation requires
11951 * name lookup) again, make statement if final ';' */
11952 std::unique_ptr<AST::CallExpr> struct_expr
11953 = parse_struct_expr_tuple_partial (std::move (path),
11954 std::move (outer_attrs));
11955 if (struct_expr == nullptr)
11956 {
11957 Error error (t2->get_locus (), "failed to parse struct expr tuple");
11958 add_error (std::move (error));
11959
11960 return ExprOrStmt::create_error ();
11961 }
11962
11963 // determine if statement if ends with semicolon
11964 if (lexer.peek_token ()->get_id () == SEMICOLON)
11965 {
11966 // statement
11967 lexer.skip_token ();
11968 std::unique_ptr<AST::ExprStmtWithoutBlock> stmt (
11969 new AST::ExprStmtWithoutBlock (std::move (struct_expr),
11970 stmt_or_expr_loc));
11971 return ExprOrStmt (std::move (stmt));
11972 }
11973
11974 // otherwise, expression
11975 return ExprOrStmt (std::move (struct_expr));
11976 }
11977 default: {
11978 // assume path - make statement if final ';'
11979 // lexer.skip_token();
11980
11981 // HACK: replace outer attributes in path
11982 path.set_outer_attrs (std::move (outer_attrs));
11983 std::unique_ptr<AST::PathInExpression> expr (
11984 new AST::PathInExpression (std::move (path)));
11985
11986 if (lexer.peek_token ()->get_id () == SEMICOLON)
11987 {
11988 lexer.skip_token ();
11989
11990 std::unique_ptr<AST::ExprStmtWithoutBlock> stmt (
11991 new AST::ExprStmtWithoutBlock (std::move (expr),
11992 stmt_or_expr_loc));
11993 return ExprOrStmt (std::move (stmt));
11994 }
11995
11996 return ExprOrStmt (std::move (expr));
11997 }
11998 }
11999}
12000
12001// Parses a struct expression field.
12002template <typename ManagedTokenSource>
12003std::unique_ptr<AST::StructExprField>
12004Parser<ManagedTokenSource>::parse_struct_expr_field ()
12005{
12006 const_TokenPtr t = lexer.peek_token ();
12007 switch (t->get_id ())
12008 {
12009 case IDENTIFIER:
12010 if (lexer.peek_token (1)->get_id () == COLON)
12011 {
12012 // struct expr field with identifier and expr
12013 Identifier ident = t->get_str ();
12014 lexer.skip_token (1);
12015
12016 // parse expression (required)
12017 std::unique_ptr<AST::Expr> expr = parse_expr ();
12018 if (expr == nullptr)
12019 {
12020 Error error (t->get_locus (),
12021 "failed to parse struct expression field with "
12022 "identifier and expression");
12023 add_error (std::move (error));
12024
12025 return nullptr;
12026 }
12027
12028 return std::unique_ptr<AST::StructExprFieldIdentifierValue> (
12029 new AST::StructExprFieldIdentifierValue (std::move (ident),
12030 std::move (expr),
12031 t->get_locus ()));
12032 }
12033 else
12034 {
12035 // struct expr field with identifier only
12036 Identifier ident = t->get_str ();
12037 lexer.skip_token ();
12038
12039 return std::unique_ptr<AST::StructExprFieldIdentifier> (
12040 new AST::StructExprFieldIdentifier (std::move (ident),
12041 t->get_locus ()));
12042 }
12043 case INT_LITERAL: {
12044 // parse tuple index field
12045 int index = atoi (t->get_str ().c_str ());
12046 lexer.skip_token ();
12047
12048 if (!skip_token (COLON))
12049 {
12050 // skip somewhere?
12051 return nullptr;
12052 }
12053
12054 // parse field expression (required)
12055 std::unique_ptr<AST::Expr> expr = parse_expr ();
12056 if (expr == nullptr)
12057 {
12058 Error error (t->get_locus (),
12059 "failed to parse expr in struct (or enum) expr "
12060 "field with tuple index");
12061 add_error (std::move (error));
12062
12063 return nullptr;
12064 }
12065
12066 return std::unique_ptr<AST::StructExprFieldIndexValue> (
12067 new AST::StructExprFieldIndexValue (index, std::move (expr),
12068 t->get_locus ()));
12069 }
12070 case DOT_DOT:
12071 /* this is a struct base and can't be parsed here, so just return
12072 * nothing without erroring */
12073
12074 return nullptr;
12075 default:
12076 add_error (
12077 Error (t->get_locus (),
12078 "unrecognised token %qs as first token of struct expr field - "
12079 "expected identifier or integer literal",
12080 t->get_token_description ()));
12081
12082 return nullptr;
12083 }
12084}
12085
12086// Parses a macro invocation or macro invocation semi.
12087template <typename ManagedTokenSource>
12088ExprOrStmt
12089Parser<ManagedTokenSource>::parse_macro_invocation_maybe_semi (
12090 AST::AttrVec outer_attrs)
12091{
12092 Location macro_locus = lexer.peek_token ()->get_locus ();
12093 AST::SimplePath macro_path = parse_simple_path ();
12094 if (macro_path.is_empty ())
12095 {
12096 Error error (lexer.peek_token ()->get_locus (),
12097 "failed to parse simple path in macro invocation or semi");
12098 add_error (std::move (error));
12099
12100 return ExprOrStmt::create_error ();
12101 }
12102
12103 if (!skip_token (EXCLAM))
12104 {
12105 return ExprOrStmt::create_error ();
12106 }
12107
12108 const_TokenPtr t3 = lexer.peek_token ();
12109 Location tok_tree_loc = t3->get_locus ();
12110
12111 AST::DelimType type = AST::PARENS;
12112 switch (t3->get_id ())
12113 {
12114 case LEFT_PAREN:
12115 type = AST::PARENS;
12116 break;
12117 case LEFT_SQUARE:
12118 type = AST::SQUARE;
12119 break;
12120 case LEFT_CURLY:
12121 type = AST::CURLY;
12122 break;
12123 default:
12124 add_error (
12125 Error (t3->get_locus (),
12126 "unrecognised token %qs in macro invocation - (opening) "
12127 "delimiter expected",
12128 t3->get_token_description ()));
12129
12130 return ExprOrStmt::create_error ();
12131 }
12132 lexer.skip_token ();
12133
12134 // parse actual token trees
12135 std::vector<std::unique_ptr<AST::TokenTree>> token_trees;
12136 auto delim_open
12137 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
12138 token_trees.push_back (std::move (delim_open));
12139
12140 t3 = lexer.peek_token ();
12141 // parse token trees until the initial delimiter token is found again
12142 while (!token_id_matches_delims (t3->get_id (), type))
12143 {
12144 std::unique_ptr<AST::TokenTree> tree = parse_token_tree ();
12145
12146 if (tree == nullptr)
12147 {
12148 Error error (t3->get_locus (),
12149 "failed to parse token tree for macro invocation (or "
12150 "semi) - found %qs",
12151 t3->get_token_description ());
12152 add_error (std::move (error));
12153
12154 return ExprOrStmt::create_error ();
12155 }
12156
12157 token_trees.push_back (std::move (tree));
12158
12159 t3 = lexer.peek_token ();
12160 }
12161 auto delim_close
12162 = std::unique_ptr<AST::Token> (new AST::Token (std::move (t3)));
12163 token_trees.push_back (std::move (delim_close));
12164
12165 // parse end delimiters
12166 t3 = lexer.peek_token ();
12167 if (token_id_matches_delims (t3->get_id (), type))
12168 {
12169 // tokens match opening delimiter, so skip.
12170 lexer.skip_token ();
12171
12172 /* with curly bracketed macros, assume it is a macro invocation unless
12173 * a semicolon is explicitly put at the end. this is not necessarily
12174 * true (i.e. context-dependence) and so may have to be fixed up via
12175 * HACKs in semantic analysis (by checking whether it is the last elem
12176 * in the vector). */
12177
12178 AST::DelimTokenTree delim_tok_tree (type, std::move (token_trees),
12179 tok_tree_loc);
12180 AST::MacroInvocData invoc_data (std::move (macro_path),
12181 std::move (delim_tok_tree));
12182
12183 if (lexer.peek_token ()->get_id () == SEMICOLON)
12184 {
12185 lexer.skip_token ();
12186
12187 std::unique_ptr<AST::MacroInvocation> stmt (
12188 new AST::MacroInvocation (std::move (invoc_data),
12189 std::move (outer_attrs), macro_locus,
12190 true));
12191 return ExprOrStmt (std::move (stmt));
12192 }
12193
12194 // otherwise, create macro invocation
12195 std::unique_ptr<AST::MacroInvocation> expr (
12196 new AST::MacroInvocation (std::move (invoc_data),
12197 std::move (outer_attrs), macro_locus));
12198 return ExprOrStmt (std::move (expr));
12199 }
12200 else
12201 {
12202 const_TokenPtr t = lexer.peek_token ();
12203 // tokens don't match opening delimiters, so produce error
12204 Error error (
12205 t->get_locus (),
12206 "unexpected token %qs - expecting closing delimiter %qs (for a "
12207 "macro invocation)",
12208 t->get_token_description (),
12209 (type == AST::PARENS ? ")" : (type == AST::SQUARE ? "]" : "}")));
12210 add_error (std::move (error));
12211
12212 return ExprOrStmt::create_error ();
12213 }
12214}
12215
12216// "Unexpected token" panic mode - flags gcc error at unexpected token
12217template <typename ManagedTokenSource>
12218void
12219Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t)
12220{
12221 Error error (t->get_locus (), "unexpected token %qs\n",
12222 t->get_token_description ());
12223 add_error (std::move (error));
12224}
12225
12226/* Crappy "error recovery" performed after error by skipping tokens until a
12227 * semi-colon is found */
12228template <typename ManagedTokenSource>
12229void
12230Parser<ManagedTokenSource>::skip_after_semicolon ()
12231{
12232 const_TokenPtr t = lexer.peek_token ();
12233
12234 while (t->get_id () != END_OF_FILE && t->get_id () != SEMICOLON)
12235 {
12236 lexer.skip_token ();
12237 t = lexer.peek_token ();
12238 }
12239
12240 if (t->get_id () == SEMICOLON)
12241 lexer.skip_token ();
12242}
12243
12244/* Checks if current token has inputted id - skips it and returns true if so,
12245 * diagnoses an error and returns false otherwise. */
12246template <typename ManagedTokenSource>
12247bool
12248Parser<ManagedTokenSource>::skip_token (TokenId token_id)
12249{
12250 return expect_token (token_id) != const_TokenPtr ();
12251}
12252
12253/* Checks if current token has inputted id - skips it and returns true if so,
12254 * returns false otherwise without diagnosing an error */
12255template <typename ManagedTokenSource>
12256bool
12257Parser<ManagedTokenSource>::maybe_skip_token (TokenId token_id)
12258{
12259 if (lexer.peek_token ()->get_id () != token_id)
12260 return false;
12261 else
12262 return skip_token (token_id);
12263}
12264
12265/* Checks the current token - if id is same as expected, skips and returns it,
12266 * otherwise diagnoses error and returns null. */
12267template <typename ManagedTokenSource>
12268const_TokenPtr
12269Parser<ManagedTokenSource>::expect_token (TokenId token_id)
12270{
12271 const_TokenPtr t = lexer.peek_token ();
12272 if (t->get_id () == token_id)
12273 {
12274 lexer.skip_token ();
12275 return t;
12276 }
12277 else
12278 {
12279 Error error (t->get_locus (), "expecting %qs but %qs found",
12280 get_token_description (token_id),
12281 t->get_token_description ());
12282 add_error (std::move (error));
12283
12284 return const_TokenPtr ();
12285 }
12286}
12287
12288// Skips all tokens until EOF or }. Don't use.
12289template <typename ManagedTokenSource>
12290void
12291Parser<ManagedTokenSource>::skip_after_end ()
12292{
12293 const_TokenPtr t = lexer.peek_token ();
12294
12295 while (t->get_id () != END_OF_FILE && t->get_id () != RIGHT_CURLY)
12296 {
12297 lexer.skip_token ();
12298 t = lexer.peek_token ();
12299 }
12300
12301 if (t->get_id () == RIGHT_CURLY)
12302 {
12303 lexer.skip_token ();
12304 }
12305}
12306
12307/* A slightly more aware error-handler that skips all tokens until it reaches
12308 * the end of the block scope (i.e. when left curly brackets = right curly
12309 * brackets). Note: assumes currently in the middle of a block. Use
12310 * skip_after_next_block to skip based on the assumption that the block
12311 * has not been entered yet. */
12312template <typename ManagedTokenSource>
12313void
12314Parser<ManagedTokenSource>::skip_after_end_block ()
12315{
12316 const_TokenPtr t = lexer.peek_token ();
12317 int curly_count = 1;
12318
12319 while (curly_count > 0 && t->get_id () != END_OF_FILE)
12320 {
12321 switch (t->get_id ())
12322 {
12323 case LEFT_CURLY:
12324 curly_count++;
12325 break;
12326 case RIGHT_CURLY:
12327 curly_count--;
12328 break;
12329 default:
12330 break;
12331 }
12332 lexer.skip_token ();
12333 t = lexer.peek_token ();
12334 }
12335}
12336
12337/* Skips tokens until the end of the next block. i.e. assumes that the block
12338 * has not been entered yet. */
12339template <typename ManagedTokenSource>
12340void
12341Parser<ManagedTokenSource>::skip_after_next_block ()
12342{
12343 const_TokenPtr t = lexer.peek_token ();
12344
12345 // initial loop - skip until EOF if no left curlies encountered
12346 while (t->get_id () != END_OF_FILE && t->get_id () != LEFT_CURLY)
12347 {
12348 lexer.skip_token ();
12349
12350 t = lexer.peek_token ();
12351 }
12352
12353 // if next token is left, skip it and then skip after the block ends
12354 if (t->get_id () == LEFT_CURLY)
12355 {
12356 lexer.skip_token ();
12357
12358 skip_after_end_block ();
12359 }
12360 // otherwise, do nothing as EOF
12361}
12362
12363/* Skips all tokens until ] (the end of an attribute) - does not skip the ]
12364 * (as designed for attribute body use) */
12365template <typename ManagedTokenSource>
12366void
12367Parser<ManagedTokenSource>::skip_after_end_attribute ()
12368{
12369 const_TokenPtr t = lexer.peek_token ();
12370
12371 while (t->get_id () != RIGHT_SQUARE)
12372 {
12373 lexer.skip_token ();
12374 t = lexer.peek_token ();
12375 }
12376
12377 // Don't skip the RIGHT_SQUARE token
12378}
12379
12380/* Pratt parser impl of parse_expr. FIXME: this is only provisional and
12381 * probably will be changed.
12382 * FIXME: this may only parse expressions without blocks as they are the only
12383 * expressions to have precedence? */
12384template <typename ManagedTokenSource>
12385std::unique_ptr<AST::Expr>
12386Parser<ManagedTokenSource>::parse_expr (int right_binding_power,
12387 AST::AttrVec outer_attrs,
12388 ParseRestrictions restrictions)
12389{
12390 const_TokenPtr current_token = lexer.peek_token ();
12391 // Special hack because we are allowed to return nullptr, in that case we
12392 // don't want to skip the token, since we don't actually parse it. But if
12393 // null isn't allowed it indicates an error, and we want to skip past that.
12394 // So return early if it is one of the tokens that ends an expression
12395 // (or at least cannot start a new expression).
12396 if (restrictions.expr_can_be_null)
12397 {
12398 TokenId id = current_token->get_id ();
12399 if (id == SEMICOLON || id == RIGHT_PAREN || id == RIGHT_CURLY
12400 || id == RIGHT_SQUARE)
12401 return nullptr;
12402 }
12403 lexer.skip_token ();
12404
12405 // parse null denotation (unary part of expression)
12406 std::unique_ptr<AST::Expr> expr
12407 = null_denotation (current_token, {}, restrictions);
12408
12409 if (expr == nullptr)
12410 {
12411 // DEBUG
12412 rust_debug ("null denotation is null; returning null for parse_expr");
12413 return nullptr;
12414 }
12415
12416 // stop parsing if find lower priority token - parse higher priority first
12417 while (right_binding_power < left_binding_power (lexer.peek_token ()))
12418 {
12419 current_token = lexer.peek_token ();
12420 lexer.skip_token ();
12421
12422 expr = left_denotation (current_token, std::move (expr),
12423 std::move (outer_attrs), restrictions);
12424
12425 if (expr == nullptr)
12426 {
12427 // DEBUG
12428 rust_debug ("left denotation is null; returning null for parse_expr");
12429
12430 return nullptr;
12431 }
12432 }
12433
12434 return expr;
12435}
12436
12437// Parse expression with lowest left binding power.
12438template <typename ManagedTokenSource>
12439std::unique_ptr<AST::Expr>
12440Parser<ManagedTokenSource>::parse_expr (AST::AttrVec outer_attrs,
12441 ParseRestrictions restrictions)
12442{
12443 return parse_expr (LBP_LOWEST, std::move (outer_attrs), restrictions);
12444}
12445
12446/* Determines action to take when finding token at beginning of expression.
12447 * FIXME: this may only apply to precedence-capable expressions (which are all
12448 * expressions without blocks), so make return type ExprWithoutBlock? It would
12449 * simplify stuff. */
12450template <typename ManagedTokenSource>
12451std::unique_ptr<AST::Expr>
12452Parser<ManagedTokenSource>::null_denotation (const_TokenPtr tok,
12453 AST::AttrVec outer_attrs,
12454 ParseRestrictions restrictions)
12455{
12456 /* note: tok is previous character in input stream, not current one, as
12457 * parse_expr skips it before passing it in */
12458
12459 /* as a Pratt parser (which works by decomposing expressions into a null
12460 * denotation and then a left denotation), null denotations handle primaries
12461 * and unary operands (but only prefix unary operands) */
12462
12463 switch (tok->get_id ())
12464 {
12465 case IDENTIFIER: {
12466 // DEBUG
12467 rust_debug ("beginning null denotation identifier handling");
12468
12469 /* best option: parse as path, then extract identifier, macro,
12470 * struct/enum, or just path info from it */
12471 AST::PathInExpression path = parse_path_in_expression_pratt (tok);
12472
12473 // DEBUG:
12474 rust_debug ("finished null denotation identifier path parsing - "
12475 "next is branching");
12476
12477 // branch on next token
12478 const_TokenPtr t = lexer.peek_token ();
12479 switch (t->get_id ())
12480 {
12481 case EXCLAM:
12482 // macro
12483 return parse_macro_invocation_partial (std::move (path),
12484 std::move (outer_attrs),
12485 restrictions);
12486 case LEFT_CURLY: {
12487 bool not_a_block
12488 = lexer.peek_token (1)->get_id () == IDENTIFIER
12489 && (lexer.peek_token (2)->get_id () == COMMA
12490 || (lexer.peek_token (2)->get_id () == COLON
12491 && (lexer.peek_token (4)->get_id () == COMMA
12492 || !can_tok_start_type (
12493 lexer.peek_token (3)->get_id ()))));
12494
12495 /* definitely not a block:
12496 * path '{' ident ','
12497 * path '{' ident ':' [anything] ','
12498 * path '{' ident ':' [not a type]
12499 * otherwise, assume block expr and thus path */
12500 // DEBUG
12501 rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ",
12502 lexer.peek_token (1)->get_token_description (),
12503 lexer.peek_token (2)->get_token_description (),
12504 lexer.peek_token (3)->get_token_description (),
12505 lexer.peek_token (4)->get_token_description ());
12506
12507 rust_debug ("can be struct expr: '%s', not a block: '%s'",
12508 restrictions.can_be_struct_expr ? "true" : "false",
12509 not_a_block ? "true" : "false");
12510
12511 // struct/enum expr struct
12512 if (!restrictions.can_be_struct_expr && !not_a_block)
12513 {
12514 // HACK: add outer attrs to path
12515 path.set_outer_attrs (std::move (outer_attrs));
12516 return std::unique_ptr<AST::PathInExpression> (
12517 new AST::PathInExpression (std::move (path)));
12518 }
12519 return parse_struct_expr_struct_partial (std::move (path),
12520 std::move (outer_attrs));
12521 }
12522 case LEFT_PAREN:
12523 // struct/enum expr tuple
12524 if (!restrictions.can_be_struct_expr)
12525 {
12526 // HACK: add outer attrs to path
12527 path.set_outer_attrs (std::move (outer_attrs));
12528 return std::unique_ptr<AST::PathInExpression> (
12529 new AST::PathInExpression (std::move (path)));
12530 }
12531 return parse_struct_expr_tuple_partial (std::move (path),
12532 std::move (outer_attrs));
12533 default:
12534 // assume path is returned if not single segment
12535 if (path.is_single_segment ())
12536 {
12537 // have to return an identifier expression or something, idk
12538 /* HACK: may have to become permanent, but this is my current
12539 * identifier expression */
12540 return std::unique_ptr<AST::IdentifierExpr> (
12541 new AST::IdentifierExpr (tok->get_str (), {},
12542 tok->get_locus ()));
12543 }
12544 // HACK: add outer attrs to path
12545 path.set_outer_attrs (std::move (outer_attrs));
12546 return std::unique_ptr<AST::PathInExpression> (
12547 new AST::PathInExpression (std::move (path)));
12548 }
12549 gcc_unreachable ();
12550 }
12551 /* FIXME: delegate to parse_literal_expr instead? would have to rejig
12552 * tokens and whatever. */
12553 /* FIXME: could also be path expression (and hence macro expression,
12554 * struct/enum expr) */
12555 case LEFT_ANGLE: {
12556 // qualified path
12557 // HACK: add outer attrs to path
12558 AST::QualifiedPathInExpression path
12559 = parse_qualified_path_in_expression (tok->get_locus ());
12560 path.set_outer_attrs (std::move (outer_attrs));
12561 return std::unique_ptr<AST::QualifiedPathInExpression> (
12562 new AST::QualifiedPathInExpression (std::move (path)));
12563 }
12564 // FIXME: for literal exprs, should outer attrs be passed in or just
12565 // ignored?
12566 case INT_LITERAL:
12567 // we should check the range, but ignore for now
12568 // encode as int?
12569 return std::unique_ptr<AST::LiteralExpr> (
12570 new AST::LiteralExpr (tok->get_str (), AST::Literal::INT,
12571 tok->get_type_hint (), {}, tok->get_locus ()));
12572 case FLOAT_LITERAL:
12573 // encode as float?
12574 return std::unique_ptr<AST::LiteralExpr> (
12575 new AST::LiteralExpr (tok->get_str (), AST::Literal::FLOAT,
12576 tok->get_type_hint (), {}, tok->get_locus ()));
12577 case STRING_LITERAL:
12578 return std::unique_ptr<AST::LiteralExpr> (
12579 new AST::LiteralExpr (tok->get_str (), AST::Literal::STRING,
12580 tok->get_type_hint (), {}, tok->get_locus ()));
12581 case BYTE_STRING_LITERAL:
12582 return std::unique_ptr<AST::LiteralExpr> (
12583 new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE_STRING,
12584 tok->get_type_hint (), {}, tok->get_locus ()));
12585 case CHAR_LITERAL:
12586 return std::unique_ptr<AST::LiteralExpr> (
12587 new AST::LiteralExpr (tok->get_str (), AST::Literal::CHAR,
12588 tok->get_type_hint (), {}, tok->get_locus ()));
12589 case BYTE_CHAR_LITERAL:
12590 return std::unique_ptr<AST::LiteralExpr> (
12591 new AST::LiteralExpr (tok->get_str (), AST::Literal::BYTE,
12592 tok->get_type_hint (), {}, tok->get_locus ()));
12593 case TRUE_LITERAL:
12594 return std::unique_ptr<AST::LiteralExpr> (
12595 new AST::LiteralExpr ("true", AST::Literal::BOOL, tok->get_type_hint (),
12596 {}, tok->get_locus ()));
12597 case FALSE_LITERAL:
12598 return std::unique_ptr<AST::LiteralExpr> (
12599 new AST::LiteralExpr ("false", AST::Literal::BOOL,
12600 tok->get_type_hint (), {}, tok->get_locus ()));
12601 case LEFT_PAREN:
12602 return parse_grouped_or_tuple_expr (std::move (outer_attrs),
12603 tok->get_locus ());
12604
12605 /*case PLUS: { // unary plus operator
12606 // invoke parse_expr recursively with appropriate priority, etc. for
12607 below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS);
12608
12609 if (expr == nullptr)
12610 return nullptr;
12611 // can only apply to integer and float expressions
12612 if (expr->get_type() != integer_type_node || expr->get_type() !=
12613 float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
12614 plus must be int or float but it is %s", print_type(expr->get_type()));
12615 return nullptr;
12616 }
12617
12618 return Tree(expr, tok->get_locus());
12619 }*/
12620 // Rust has no unary plus operator
12621 case MINUS: { // unary minus
12622 ParseRestrictions entered_from_unary;
12623 entered_from_unary.entered_from_unary = true;
12624 if (!restrictions.can_be_struct_expr)
12625 entered_from_unary.can_be_struct_expr = false;
12626 std::unique_ptr<AST::Expr> expr
12627 = parse_expr (LBP_UNARY_MINUS, {}, entered_from_unary);
12628
12629 if (expr == nullptr)
12630 return nullptr;
12631 // can only apply to integer and float expressions
12632 /*if (expr.get_type() != integer_type_node || expr.get_type() !=
12633 float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
12634 minus must be int or float but it is %s",
12635 print_type(expr.get_type())); return Tree::error();
12636 }*/
12637 /* FIXME: when implemented the "get type" method on expr, ensure it is
12638 * int or float type (except unsigned int). Actually, this would
12639 * probably have to be done in semantic analysis (as type checking).
12640 */
12641
12642 /* FIXME: allow outer attributes on these expressions by having an
12643 * outer attrs parameter in function*/
12644 return std::unique_ptr<AST::NegationExpr> (
12645 new AST::NegationExpr (std::move (expr), NegationOperator::NEGATE,
12646 std::move (outer_attrs), tok->get_locus ()));
12647 }
12648 case EXCLAM: { // logical or bitwise not
12649 ParseRestrictions entered_from_unary;
12650 entered_from_unary.entered_from_unary = true;
12651 if (!restrictions.can_be_struct_expr)
12652 entered_from_unary.can_be_struct_expr = false;
12653 std::unique_ptr<AST::Expr> expr
12654 = parse_expr (LBP_UNARY_EXCLAM, {}, entered_from_unary);
12655
12656 if (expr == nullptr)
12657 return nullptr;
12658 // can only apply to boolean expressions
12659 /*if (expr.get_type() != boolean_type_node) {
12660 rust_error_at(tok->get_locus(),
12661 "operand of logical not must be a boolean but it is %s",
12662 print_type(expr.get_type()));
12663 return Tree::error();
12664 }*/
12665 /* FIXME: type checking for boolean or integer expressions in semantic
12666 * analysis */
12667
12668 // FIXME: allow outer attributes on these expressions
12669 return std::unique_ptr<AST::NegationExpr> (
12670 new AST::NegationExpr (std::move (expr), NegationOperator::NOT,
12671 std::move (outer_attrs), tok->get_locus ()));
12672 }
12673 case ASTERISK: {
12674 /* pointer dereference only - HACK: as struct expressions should
12675 * always be value expressions, cannot be dereferenced */
12676 ParseRestrictions entered_from_unary;
12677 entered_from_unary.entered_from_unary = true;
12678 entered_from_unary.can_be_struct_expr = false;
12679 std::unique_ptr<AST::Expr> expr
12680 = parse_expr (LBP_UNARY_ASTERISK, {}, entered_from_unary);
12681 // FIXME: allow outer attributes on expression
12682 return std::unique_ptr<AST::DereferenceExpr> (
12683 new AST::DereferenceExpr (std::move (expr), std::move (outer_attrs),
12684 tok->get_locus ()));
12685 }
12686 case AMP: {
12687 // (single) "borrow" expression - shared (mutable) or immutable
12688 std::unique_ptr<AST::Expr> expr = nullptr;
12689 bool is_mut_borrow = false;
12690
12691 /* HACK: as struct expressions should always be value expressions,
12692 * cannot be referenced */
12693 ParseRestrictions entered_from_unary;
12694 entered_from_unary.entered_from_unary = true;
12695 entered_from_unary.can_be_struct_expr = false;
12696
12697 if (lexer.peek_token ()->get_id () == MUT)
12698 {
12699 lexer.skip_token ();
12700 expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
12701 is_mut_borrow = true;
12702 }
12703 else
12704 {
12705 expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
12706 }
12707
12708 // FIXME: allow outer attributes on expression
12709 return std::unique_ptr<AST::BorrowExpr> (
12710 new AST::BorrowExpr (std::move (expr), is_mut_borrow, false,
12711 std::move (outer_attrs), tok->get_locus ()));
12712 }
12713 case LOGICAL_AND: {
12714 // (double) "borrow" expression - shared (mutable) or immutable
12715 std::unique_ptr<AST::Expr> expr = nullptr;
12716 bool is_mut_borrow = false;
12717
12718 ParseRestrictions entered_from_unary;
12719 entered_from_unary.entered_from_unary = true;
12720
12721 if (lexer.peek_token ()->get_id () == MUT)
12722 {
12723 lexer.skip_token ();
12724 expr = parse_expr (LBP_UNARY_AMP_MUT, {}, entered_from_unary);
12725 is_mut_borrow = true;
12726 }
12727 else
12728 {
12729 expr = parse_expr (LBP_UNARY_AMP, {}, entered_from_unary);
12730 }
12731
12732 // FIXME: allow outer attributes on expression
12733 return std::unique_ptr<AST::BorrowExpr> (
12734 new AST::BorrowExpr (std::move (expr), is_mut_borrow, true,
12735 std::move (outer_attrs), tok->get_locus ()));
12736 }
12737 case SCOPE_RESOLUTION: {
12738 // TODO: fix: this is for global paths, i.e. std::string::whatever
12739 Error error (tok->get_locus (),
12740 "found null denotation scope resolution operator, and "
12741 "have not written handling for it");
12742 add_error (std::move (error));
12743
12744 return nullptr;
12745 }
12746 case SELF:
12747 case SELF_ALIAS:
12748 case DOLLAR_SIGN:
12749 case CRATE:
12750 case SUPER: {
12751 // DEBUG
12752 rust_debug ("beginning null denotation "
12753 "self/self-alias/dollar/crate/super handling");
12754
12755 /* best option: parse as path, then extract identifier, macro,
12756 * struct/enum, or just path info from it */
12757 AST::PathInExpression path = parse_path_in_expression_pratt (tok);
12758
12759 // DEBUG
12760 rust_debug (
12761 "just finished parsing path (going to disambiguate) - peeked "
12762 "token is '%s'",
12763 lexer.peek_token ()->get_token_description ());
12764
12765 // HACK: always make "self" by itself a path (regardless of next
12766 // tokens)
12767 if (tok->get_id () == SELF && path.is_single_segment ())
12768 {
12769 // HACK: add outer attrs to path
12770 path.set_outer_attrs (std::move (outer_attrs));
12771 return std::unique_ptr<AST::PathInExpression> (
12772 new AST::PathInExpression (std::move (path)));
12773 }
12774
12775 // branch on next token
12776 const_TokenPtr t = lexer.peek_token ();
12777 switch (t->get_id ())
12778 {
12779 case EXCLAM:
12780 // macro
12781 return parse_macro_invocation_partial (std::move (path),
12782 std::move (outer_attrs));
12783 case LEFT_CURLY: {
12784 // struct/enum expr struct
12785 rust_debug ("can_be_struct_expr: %s",
12786 restrictions.can_be_struct_expr ? "true" : "false");
12787
12788 bool not_a_block
12789 = lexer.peek_token (1)->get_id () == IDENTIFIER
12790 && (lexer.peek_token (2)->get_id () == COMMA
12791 || (lexer.peek_token (2)->get_id () == COLON
12792 && (lexer.peek_token (4)->get_id () == COMMA
12793 || !can_tok_start_type (
12794 lexer.peek_token (3)->get_id ()))));
12795
12796 if (!restrictions.can_be_struct_expr && !not_a_block)
12797 {
12798 // assume path is returned
12799 // HACK: add outer attributes to path
12800 path.set_outer_attrs (std::move (outer_attrs));
12801 return std::unique_ptr<AST::PathInExpression> (
12802 new AST::PathInExpression (std::move (path)));
12803 }
12804 return parse_struct_expr_struct_partial (std::move (path),
12805 std::move (outer_attrs));
12806 }
12807 case LEFT_PAREN:
12808 // struct/enum expr tuple
12809 if (!restrictions.can_be_struct_expr)
12810 {
12811 // assume path is returned
12812 // HACK: add outer attributes to path
12813 path.set_outer_attrs (std::move (outer_attrs));
12814 return std::unique_ptr<AST::PathInExpression> (
12815 new AST::PathInExpression (std::move (path)));
12816 }
12817 return parse_struct_expr_tuple_partial (std::move (path),
12818 std::move (outer_attrs));
12819 default:
12820 // assume path is returned
12821 // HACK: add outer attributes to path
12822 path.set_outer_attrs (std::move (outer_attrs));
12823 return std::unique_ptr<AST::PathInExpression> (
12824 new AST::PathInExpression (std::move (path)));
12825 }
12826 gcc_unreachable ();
12827 }
12828 case OR:
12829 case PIPE:
12830 case MOVE:
12831 // closure expression
12832 return parse_closure_expr_pratt (tok, std::move (outer_attrs));
12833 case DOT_DOT:
12834 // either "range to" or "range full" expressions
12835 return parse_nud_range_exclusive_expr (tok, std::move (outer_attrs));
12836 case DOT_DOT_EQ:
12837 // range to inclusive expr
12838 return parse_range_to_inclusive_expr (tok, std::move (outer_attrs));
12839 case RETURN_TOK:
12840 // FIXME: is this really a null denotation expression?
12841 return parse_return_expr (std::move (outer_attrs), tok->get_locus ());
12842 case BREAK:
12843 // FIXME: is this really a null denotation expression?
12844 return parse_break_expr (std::move (outer_attrs), tok->get_locus ());
12845 case CONTINUE:
12846 return parse_continue_expr (std::move (outer_attrs), tok->get_locus ());
12847 case LEFT_CURLY:
12848 // ok - this is an expression with block for once.
12849 return parse_block_expr (std::move (outer_attrs), tok->get_locus ());
12850 case IF:
12851 // if or if let, so more lookahead to find out
12852 if (lexer.peek_token (1)->get_id () == LET)
12853 {
12854 // if let expr
12855 return parse_if_let_expr (std::move (outer_attrs), tok->get_locus ());
12856 }
12857 else
12858 {
12859 // if expr
12860 return parse_if_expr (std::move (outer_attrs), tok->get_locus ());
12861 }
12862 case LOOP:
12863 return parse_loop_expr (std::move (outer_attrs), AST::LoopLabel::error (),
12864 tok->get_locus ());
12865 case WHILE:
12866 return parse_while_loop_expr (std::move (outer_attrs),
12867 AST::LoopLabel::error (),
12868 tok->get_locus ());
12869 case MATCH_TOK:
12870 // also an expression with block
12871 return parse_match_expr (std::move (outer_attrs), tok->get_locus ());
12872 case LEFT_SQUARE:
12873 // array definition expr (not indexing)
12874 return parse_array_expr (std::move (outer_attrs), tok->get_locus ());
12875 case UNSAFE:
12876 return parse_unsafe_block_expr (std::move (outer_attrs),
12877 tok->get_locus ());
12878 default:
12879 if (!restrictions.expr_can_be_null)
12880 add_error (Error (tok->get_locus (),
12881 "found unexpected token %qs in null denotation",
12882 tok->get_token_description ()));
12883 return nullptr;
12884 }
12885}
12886
12887/* Called for each token that can appear in infix (between) position. Can be
12888 * operators or other punctuation. Returns a function pointer to member
12889 * function that implements the left denotation for the token given. */
12890template <typename ManagedTokenSource>
12891std::unique_ptr<AST::Expr>
12892Parser<ManagedTokenSource>::left_denotation (const_TokenPtr tok,
12893 std::unique_ptr<AST::Expr> left,
12894 AST::AttrVec outer_attrs,
12895 ParseRestrictions restrictions)
12896{
12897 // Token passed in has already been skipped, so peek gives "next" token
12898 switch (tok->get_id ())
12899 {
12900 // FIXME: allow for outer attributes to be applied
12901 case QUESTION_MARK: {
12902 Location left_locus = left->get_locus ();
12903 // error propagation expression - unary postfix
12904 return std::unique_ptr<AST::ErrorPropagationExpr> (
12905 new AST::ErrorPropagationExpr (std::move (left),
12906 std::move (outer_attrs), left_locus));
12907 }
12908 case PLUS:
12909 // sum expression - binary infix
12910 /*return parse_binary_plus_expr (tok, std::move (left),
12911 std::move (outer_attrs), restrictions);*/
12912 return parse_arithmetic_or_logical_expr (tok, std::move (left),
12913 std::move (outer_attrs),
12914 ArithmeticOrLogicalOperator::ADD,
12915 restrictions);
12916 case MINUS:
12917 // difference expression - binary infix
12918 /*return parse_binary_minus_expr (tok, std::move (left),
12919 std::move (outer_attrs),
12920 restrictions);*/
12921 return parse_arithmetic_or_logical_expr (
12922 tok, std::move (left), std::move (outer_attrs),
12923 ArithmeticOrLogicalOperator::SUBTRACT, restrictions);
12924 case ASTERISK:
12925 // product expression - binary infix
12926 /*return parse_binary_mult_expr (tok, std::move (left),
12927 std::move (outer_attrs), restrictions);*/
12928 return parse_arithmetic_or_logical_expr (
12929 tok, std::move (left), std::move (outer_attrs),
12930 ArithmeticOrLogicalOperator::MULTIPLY, restrictions);
12931 case DIV:
12932 // quotient expression - binary infix
12933 /*return parse_binary_div_expr (tok, std::move (left),
12934 std::move (outer_attrs), restrictions);*/
12935 return parse_arithmetic_or_logical_expr (
12936 tok, std::move (left), std::move (outer_attrs),
12937 ArithmeticOrLogicalOperator::DIVIDE, restrictions);
12938 case PERCENT:
12939 // modulo expression - binary infix
12940 /*return parse_binary_mod_expr (tok, std::move (left),
12941 std::move (outer_attrs), restrictions);*/
12942 return parse_arithmetic_or_logical_expr (
12943 tok, std::move (left), std::move (outer_attrs),
12944 ArithmeticOrLogicalOperator::MODULUS, restrictions);
12945 case AMP:
12946 // logical or bitwise and expression - binary infix
12947 /*return parse_bitwise_and_expr (tok, std::move (left),
12948 std::move (outer_attrs), restrictions);*/
12949 return parse_arithmetic_or_logical_expr (
12950 tok, std::move (left), std::move (outer_attrs),
12951 ArithmeticOrLogicalOperator::BITWISE_AND, restrictions);
12952 case PIPE:
12953 // logical or bitwise or expression - binary infix
12954 /*return parse_bitwise_or_expr (tok, std::move (left),
12955 std::move (outer_attrs), restrictions);*/
12956 return parse_arithmetic_or_logical_expr (
12957 tok, std::move (left), std::move (outer_attrs),
12958 ArithmeticOrLogicalOperator::BITWISE_OR, restrictions);
12959 case CARET:
12960 // logical or bitwise xor expression - binary infix
12961 /*return parse_bitwise_xor_expr (tok, std::move (left),
12962 std::move (outer_attrs), restrictions);*/
12963 return parse_arithmetic_or_logical_expr (
12964 tok, std::move (left), std::move (outer_attrs),
12965 ArithmeticOrLogicalOperator::BITWISE_XOR, restrictions);
12966 case LEFT_SHIFT:
12967 // left shift expression - binary infix
12968 /*return parse_left_shift_expr (tok, std::move (left),
12969 std::move (outer_attrs), restrictions);*/
12970 return parse_arithmetic_or_logical_expr (
12971 tok, std::move (left), std::move (outer_attrs),
12972 ArithmeticOrLogicalOperator::LEFT_SHIFT, restrictions);
12973 case RIGHT_SHIFT:
12974 // right shift expression - binary infix
12975 /*return parse_right_shift_expr (tok, std::move (left),
12976 std::move (outer_attrs), restrictions);*/
12977 return parse_arithmetic_or_logical_expr (
12978 tok, std::move (left), std::move (outer_attrs),
12979 ArithmeticOrLogicalOperator::RIGHT_SHIFT, restrictions);
12980 case EQUAL_EQUAL:
12981 // equal to expression - binary infix (no associativity)
12982 /*return parse_binary_equal_expr (tok, std::move (left),
12983 std::move (outer_attrs),
12984 restrictions);*/
12985 return parse_comparison_expr (tok, std::move (left),
12986 std::move (outer_attrs),
12987 ComparisonOperator::EQUAL, restrictions);
12988 case NOT_EQUAL:
12989 // not equal to expression - binary infix (no associativity)
12990 /*return parse_binary_not_equal_expr (tok, std::move (left),
12991 std::move (outer_attrs),
12992 restrictions);*/
12993 return parse_comparison_expr (tok, std::move (left),
12994 std::move (outer_attrs),
12995 ComparisonOperator::NOT_EQUAL,
12996 restrictions);
12997 case RIGHT_ANGLE:
12998 // greater than expression - binary infix (no associativity)
12999 /*return parse_binary_greater_than_expr (tok, std::move (left),
13000 std::move (outer_attrs),
13001 restrictions);*/
13002 return parse_comparison_expr (tok, std::move (left),
13003 std::move (outer_attrs),
13004 ComparisonOperator::GREATER_THAN,
13005 restrictions);
13006 case LEFT_ANGLE:
13007 // less than expression - binary infix (no associativity)
13008 /*return parse_binary_less_than_expr (tok, std::move (left),
13009 std::move (outer_attrs),
13010 restrictions);*/
13011 return parse_comparison_expr (tok, std::move (left),
13012 std::move (outer_attrs),
13013 ComparisonOperator::LESS_THAN,
13014 restrictions);
13015 case GREATER_OR_EQUAL:
13016 // greater than or equal to expression - binary infix (no associativity)
13017 /*return parse_binary_greater_equal_expr (tok, std::move (left),
13018 std::move (outer_attrs),
13019 restrictions);*/
13020 return parse_comparison_expr (tok, std::move (left),
13021 std::move (outer_attrs),
13022 ComparisonOperator::GREATER_OR_EQUAL,
13023 restrictions);
13024 case LESS_OR_EQUAL:
13025 // less than or equal to expression - binary infix (no associativity)
13026 /*return parse_binary_less_equal_expr (tok, std::move (left),
13027 std::move (outer_attrs),
13028 restrictions);*/
13029 return parse_comparison_expr (tok, std::move (left),
13030 std::move (outer_attrs),
13031 ComparisonOperator::LESS_OR_EQUAL,
13032 restrictions);
13033 case OR:
13034 // lazy logical or expression - binary infix
13035 return parse_lazy_or_expr (tok, std::move (left), std::move (outer_attrs),
13036 restrictions);
13037 case LOGICAL_AND:
13038 // lazy logical and expression - binary infix
13039 return parse_lazy_and_expr (tok, std::move (left),
13040 std::move (outer_attrs), restrictions);
13041 case AS:
13042 /* type cast expression - kind of binary infix (RHS is actually a
13043 * TypeNoBounds) */
13044 return parse_type_cast_expr (tok, std::move (left),
13045 std::move (outer_attrs), restrictions);
13046 case EQUAL:
13047 // assignment expression - binary infix (note right-to-left
13048 // associativity)
13049 return parse_assig_expr (tok, std::move (left), std::move (outer_attrs),
13050 restrictions);
13051 case PLUS_EQ:
13052 /* plus-assignment expression - binary infix (note right-to-left
13053 * associativity) */
13054 /*return parse_plus_assig_expr (tok, std::move (left),
13055 std::move (outer_attrs), restrictions);*/
13056 return parse_compound_assignment_expr (tok, std::move (left),
13057 std::move (outer_attrs),
13058 CompoundAssignmentOperator::ADD,
13059 restrictions);
13060 case MINUS_EQ:
13061 /* minus-assignment expression - binary infix (note right-to-left
13062 * associativity) */
13063 /*return parse_minus_assig_expr (tok, std::move (left),
13064 std::move (outer_attrs), restrictions);*/
13065 return parse_compound_assignment_expr (
13066 tok, std::move (left), std::move (outer_attrs),
13067 CompoundAssignmentOperator::SUBTRACT, restrictions);
13068 case ASTERISK_EQ:
13069 /* multiply-assignment expression - binary infix (note right-to-left
13070 * associativity) */
13071 /*return parse_mult_assig_expr (tok, std::move (left),
13072 std::move (outer_attrs), restrictions);*/
13073 return parse_compound_assignment_expr (
13074 tok, std::move (left), std::move (outer_attrs),
13075 CompoundAssignmentOperator::MULTIPLY, restrictions);
13076 case DIV_EQ:
13077 /* division-assignment expression - binary infix (note right-to-left
13078 * associativity) */
13079 /*return parse_div_assig_expr (tok, std::move (left),
13080 std::move (outer_attrs), restrictions);*/
13081 return parse_compound_assignment_expr (tok, std::move (left),
13082 std::move (outer_attrs),
13083 CompoundAssignmentOperator::DIVIDE,
13084 restrictions);
13085 case PERCENT_EQ:
13086 /* modulo-assignment expression - binary infix (note right-to-left
13087 * associativity) */
13088 /*return parse_mod_assig_expr (tok, std::move (left),
13089 std::move (outer_attrs), restrictions);*/
13090 return parse_compound_assignment_expr (
13091 tok, std::move (left), std::move (outer_attrs),
13092 CompoundAssignmentOperator::MODULUS, restrictions);
13093 case AMP_EQ:
13094 /* bitwise and-assignment expression - binary infix (note right-to-left
13095 * associativity) */
13096 /*return parse_and_assig_expr (tok, std::move (left),
13097 std::move (outer_attrs), restrictions);*/
13098 return parse_compound_assignment_expr (
13099 tok, std::move (left), std::move (outer_attrs),
13100 CompoundAssignmentOperator::BITWISE_AND, restrictions);
13101 case PIPE_EQ:
13102 /* bitwise or-assignment expression - binary infix (note right-to-left
13103 * associativity) */
13104 /*return parse_or_assig_expr (tok, std::move (left),
13105 std::move (outer_attrs), restrictions);*/
13106 return parse_compound_assignment_expr (
13107 tok, std::move (left), std::move (outer_attrs),
13108 CompoundAssignmentOperator::BITWISE_OR, restrictions);
13109 case CARET_EQ:
13110 /* bitwise xor-assignment expression - binary infix (note right-to-left
13111 * associativity) */
13112 /*return parse_xor_assig_expr (tok, std::move (left),
13113 std::move (outer_attrs), restrictions);*/
13114 return parse_compound_assignment_expr (
13115 tok, std::move (left), std::move (outer_attrs),
13116 CompoundAssignmentOperator::BITWISE_XOR, restrictions);
13117 case LEFT_SHIFT_EQ:
13118 /* left shift-assignment expression - binary infix (note right-to-left
13119 * associativity) */
13120 /*return parse_left_shift_assig_expr (tok, std::move (left),
13121 std::move (outer_attrs),
13122 restrictions);*/
13123 return parse_compound_assignment_expr (
13124 tok, std::move (left), std::move (outer_attrs),
13125 CompoundAssignmentOperator::LEFT_SHIFT, restrictions);
13126 case RIGHT_SHIFT_EQ:
13127 /* right shift-assignment expression - binary infix (note right-to-left
13128 * associativity) */
13129 /*return parse_right_shift_assig_expr (tok, std::move (left),
13130 std::move (outer_attrs),
13131 restrictions);*/
13132 return parse_compound_assignment_expr (
13133 tok, std::move (left), std::move (outer_attrs),
13134 CompoundAssignmentOperator::RIGHT_SHIFT, restrictions);
13135 case DOT_DOT:
13136 /* range exclusive expression - binary infix (no associativity)
13137 * either "range" or "range from" */
13138 return parse_led_range_exclusive_expr (tok, std::move (left),
13139 std::move (outer_attrs),
13140 restrictions);
13141 case DOT_DOT_EQ:
13142 /* range inclusive expression - binary infix (no associativity)
13143 * unambiguously RangeInclusiveExpr */
13144 return parse_range_inclusive_expr (tok, std::move (left),
13145 std::move (outer_attrs), restrictions);
13146 case SCOPE_RESOLUTION:
13147 // path expression - binary infix? FIXME should this even be parsed
13148 // here?
13149 add_error (
13150 Error (tok->get_locus (),
13151 "found scope resolution operator in left denotation "
13152 "function - this should probably be handled elsewhere"));
13153
13154 return nullptr;
13155 case DOT: {
13156 /* field expression or method call - relies on parentheses after next
13157 * identifier or await if token after is "await" (unary postfix) or
13158 * tuple index if token after is a decimal int literal */
13159
13160 const_TokenPtr next_tok = lexer.peek_token ();
13161 if (next_tok->get_id () == IDENTIFIER
13162 && next_tok->get_str () == "await")
13163 {
13164 // await expression
13165 return parse_await_expr (tok, std::move (left),
13166 std::move (outer_attrs));
13167 }
13168 else if (next_tok->get_id () == INT_LITERAL)
13169 {
13170 // tuple index expression - TODO check for decimal int literal
13171 return parse_tuple_index_expr (tok, std::move (left),
13172 std::move (outer_attrs),
13173 restrictions);
13174 }
13175 else if (next_tok->get_id () == IDENTIFIER
13176 && lexer.peek_token (1)->get_id () != LEFT_PAREN
13177 && lexer.peek_token (1)->get_id () != SCOPE_RESOLUTION)
13178 {
13179 /* field expression (or should be) - FIXME: scope resolution right
13180 * after identifier should always be method, I'm pretty sure */
13181 return parse_field_access_expr (tok, std::move (left),
13182 std::move (outer_attrs),
13183 restrictions);
13184 }
13185 else
13186 {
13187 // method call (probably)
13188 return parse_method_call_expr (tok, std::move (left),
13189 std::move (outer_attrs),
13190 restrictions);
13191 }
13192 }
13193 case LEFT_PAREN:
13194 // function call - method call is based on dot notation first
13195 return parse_function_call_expr (tok, std::move (left),
13196 std::move (outer_attrs), restrictions);
13197 case LEFT_SQUARE:
13198 // array or slice index expression (pseudo binary infix)
13199 return parse_index_expr (tok, std::move (left), std::move (outer_attrs),
13200 restrictions);
13201 case FLOAT_LITERAL:
13202 /* HACK: get around lexer mis-identifying '.0' or '.1' or whatever as a
13203 * float literal - TODO does this happen anymore? It shouldn't. */
13204 return parse_tuple_index_expr_float (tok, std::move (left),
13205 std::move (outer_attrs),
13206 restrictions);
13207 default:
13208 add_error (Error (tok->get_locus (),
13209 "found unexpected token %qs in left denotation",
13210 tok->get_token_description ()));
13211
13212 return nullptr;
13213 }
13214}
13215
13216/* Returns the left binding power for the given ArithmeticOrLogicalExpr type.
13217 * TODO make constexpr? Would that even do anything useful? */
13218inline binding_powers
13219get_lbp_for_arithmetic_or_logical_expr (
13220 AST::ArithmeticOrLogicalExpr::ExprType expr_type)
13221{
13222 switch (expr_type)
13223 {
13224 case ArithmeticOrLogicalOperator::ADD:
13225 return LBP_PLUS;
13226 case ArithmeticOrLogicalOperator::SUBTRACT:
13227 return LBP_MINUS;
13228 case ArithmeticOrLogicalOperator::MULTIPLY:
13229 return LBP_MUL;
13230 case ArithmeticOrLogicalOperator::DIVIDE:
13231 return LBP_DIV;
13232 case ArithmeticOrLogicalOperator::MODULUS:
13233 return LBP_MOD;
13234 case ArithmeticOrLogicalOperator::BITWISE_AND:
13235 return LBP_AMP;
13236 case ArithmeticOrLogicalOperator::BITWISE_OR:
13237 return LBP_PIPE;
13238 case ArithmeticOrLogicalOperator::BITWISE_XOR:
13239 return LBP_CARET;
13240 case ArithmeticOrLogicalOperator::LEFT_SHIFT:
13241 return LBP_L_SHIFT;
13242 case ArithmeticOrLogicalOperator::RIGHT_SHIFT:
13243 return LBP_R_SHIFT;
13244 default:
13245 // WTF? should not happen, this is an error
13246 gcc_unreachable ();
13247
13248 return LBP_PLUS;
13249 }
13250}
13251
13252// Parses an arithmetic or logical expression (with Pratt parsing).
13253template <typename ManagedTokenSource>
13254std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13255Parser<ManagedTokenSource>::parse_arithmetic_or_logical_expr (
13256 const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
13257 AST::ArithmeticOrLogicalExpr::ExprType expr_type,
13258 ParseRestrictions restrictions)
13259{
13260 // parse RHS (as tok has already been consumed in parse_expression)
13261 std::unique_ptr<AST::Expr> right
13262 = parse_expr (get_lbp_for_arithmetic_or_logical_expr (expr_type),
13263 AST::AttrVec (), restrictions);
13264 if (right == nullptr)
13265 return nullptr;
13266
13267 // TODO: check types. actually, do so during semantic analysis
13268 Location locus = left->get_locus ();
13269
13270 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13271 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13272 expr_type, locus));
13273}
13274
13275// Parses a binary addition expression (with Pratt parsing).
13276template <typename ManagedTokenSource>
13277std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13278Parser<ManagedTokenSource>::parse_binary_plus_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_PLUS, AST::AttrVec (), restrictions);
13285 if (right == nullptr)
13286 return nullptr;
13287
13288 // TODO: check types. actually, do so during semantic analysis
13289 Location locus = left->get_locus ();
13290
13291 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13292 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13293 ArithmeticOrLogicalOperator::ADD, locus));
13294}
13295
13296// Parses a binary subtraction expression (with Pratt parsing).
13297template <typename ManagedTokenSource>
13298std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13299Parser<ManagedTokenSource>::parse_binary_minus_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_MINUS, AST::AttrVec (), restrictions);
13306 if (right == nullptr)
13307 return nullptr;
13308
13309 // TODO: check types. actually, do so during semantic analysis
13310 Location locus = left->get_locus ();
13311
13312 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13313 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13314 ArithmeticOrLogicalOperator::SUBTRACT,
13315 locus));
13316}
13317
13318// Parses a binary multiplication expression (with Pratt parsing).
13319template <typename ManagedTokenSource>
13320std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13321Parser<ManagedTokenSource>::parse_binary_mult_expr (
13322 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13323 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13324{
13325 // parse RHS (as tok has already been consumed in parse_expression)
13326 std::unique_ptr<AST::Expr> right
13327 = parse_expr (LBP_MUL, AST::AttrVec (), restrictions);
13328 if (right == nullptr)
13329 return nullptr;
13330
13331 // TODO: check types. actually, do so during semantic analysis
13332 Location locus = left->get_locus ();
13333
13334 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13335 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13336 ArithmeticOrLogicalOperator::MULTIPLY,
13337 locus));
13338}
13339
13340// Parses a binary division expression (with Pratt parsing).
13341template <typename ManagedTokenSource>
13342std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13343Parser<ManagedTokenSource>::parse_binary_div_expr (
13344 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13345 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13346{
13347 // parse RHS (as tok has already been consumed in parse_expression)
13348 std::unique_ptr<AST::Expr> right
13349 = parse_expr (LBP_DIV, AST::AttrVec (), restrictions);
13350 if (right == nullptr)
13351 return nullptr;
13352
13353 // TODO: check types. actually, do so during semantic analysis
13354 Location locus = left->get_locus ();
13355
13356 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13357 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13358 ArithmeticOrLogicalOperator::DIVIDE,
13359 locus));
13360}
13361
13362// Parses a binary modulo expression (with Pratt parsing).
13363template <typename ManagedTokenSource>
13364std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13365Parser<ManagedTokenSource>::parse_binary_mod_expr (
13366 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13367 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13368{
13369 // parse RHS (as tok has already been consumed in parse_expression)
13370 std::unique_ptr<AST::Expr> right
13371 = parse_expr (LBP_MOD, AST::AttrVec (), restrictions);
13372 if (right == nullptr)
13373 return nullptr;
13374
13375 // TODO: check types. actually, do so during semantic analysis
13376 Location locus = left->get_locus ();
13377
13378 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13379 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13380 ArithmeticOrLogicalOperator::MODULUS,
13381 locus));
13382}
13383
13384/* Parses a binary bitwise (or eager logical) and expression (with Pratt
13385 * parsing). */
13386template <typename ManagedTokenSource>
13387std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13388Parser<ManagedTokenSource>::parse_bitwise_and_expr (
13389 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13390 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13391{
13392 // parse RHS (as tok has already been consumed in parse_expression)
13393 std::unique_ptr<AST::Expr> right
13394 = parse_expr (LBP_AMP, AST::AttrVec (), restrictions);
13395 if (right == nullptr)
13396 return nullptr;
13397
13398 // TODO: check types. actually, do so during semantic analysis
13399 Location locus = left->get_locus ();
13400
13401 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13402 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13403 ArithmeticOrLogicalOperator::BITWISE_AND,
13404 locus));
13405}
13406
13407/* Parses a binary bitwise (or eager logical) or expression (with Pratt
13408 * parsing). */
13409template <typename ManagedTokenSource>
13410std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13411Parser<ManagedTokenSource>::parse_bitwise_or_expr (
13412 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13413 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13414{
13415 // parse RHS (as tok has already been consumed in parse_expression)
13416 std::unique_ptr<AST::Expr> right
13417 = parse_expr (LBP_PIPE, AST::AttrVec (), restrictions);
13418 if (right == nullptr)
13419 return nullptr;
13420
13421 // TODO: check types. actually, do so during semantic analysis
13422 Location locus = left->get_locus ();
13423
13424 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13425 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13426 ArithmeticOrLogicalOperator::BITWISE_OR,
13427 locus));
13428}
13429
13430/* Parses a binary bitwise (or eager logical) xor expression (with Pratt
13431 * parsing). */
13432template <typename ManagedTokenSource>
13433std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13434Parser<ManagedTokenSource>::parse_bitwise_xor_expr (
13435 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13436 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13437{
13438 // parse RHS (as tok has already been consumed in parse_expression)
13439 std::unique_ptr<AST::Expr> right
13440 = parse_expr (LBP_CARET, AST::AttrVec (), restrictions);
13441 if (right == nullptr)
13442 return nullptr;
13443
13444 // TODO: check types. actually, do so during semantic analysis
13445 Location locus = left->get_locus ();
13446
13447 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13448 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13449 ArithmeticOrLogicalOperator::BITWISE_XOR,
13450 locus));
13451}
13452
13453// Parses a binary left shift expression (with Pratt parsing).
13454template <typename ManagedTokenSource>
13455std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13456Parser<ManagedTokenSource>::parse_left_shift_expr (
13457 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13458 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13459{
13460 // parse RHS (as tok has already been consumed in parse_expression)
13461 std::unique_ptr<AST::Expr> right
13462 = parse_expr (LBP_L_SHIFT, AST::AttrVec (), restrictions);
13463 if (right == nullptr)
13464 return nullptr;
13465
13466 // TODO: check types. actually, do so during semantic analysis
13467 Location locus = left->get_locus ();
13468
13469 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13470 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13471 ArithmeticOrLogicalOperator::LEFT_SHIFT,
13472 locus));
13473}
13474
13475// Parses a binary right shift expression (with Pratt parsing).
13476template <typename ManagedTokenSource>
13477std::unique_ptr<AST::ArithmeticOrLogicalExpr>
13478Parser<ManagedTokenSource>::parse_right_shift_expr (
13479 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13480 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13481{
13482 // parse RHS (as tok has already been consumed in parse_expression)
13483 std::unique_ptr<AST::Expr> right
13484 = parse_expr (LBP_R_SHIFT, AST::AttrVec (), restrictions);
13485 if (right == nullptr)
13486 return nullptr;
13487
13488 // TODO: check types. actually, do so during semantic analysis
13489 Location locus = left->get_locus ();
13490
13491 return std::unique_ptr<AST::ArithmeticOrLogicalExpr> (
13492 new AST::ArithmeticOrLogicalExpr (std::move (left), std::move (right),
13493 ArithmeticOrLogicalOperator::RIGHT_SHIFT,
13494 locus));
13495}
13496
13497/* Returns the left binding power for the given ComparisonExpr type.
13498 * TODO make constexpr? Would that even do anything useful? */
13499inline binding_powers
13500get_lbp_for_comparison_expr (AST::ComparisonExpr::ExprType expr_type)
13501{
13502 switch (expr_type)
13503 {
13504 case ComparisonOperator::EQUAL:
13505 return LBP_EQUAL;
13506 case ComparisonOperator::NOT_EQUAL:
13507 return LBP_NOT_EQUAL;
13508 case ComparisonOperator::GREATER_THAN:
13509 return LBP_GREATER_THAN;
13510 case ComparisonOperator::LESS_THAN:
13511 return LBP_SMALLER_THAN;
13512 case ComparisonOperator::GREATER_OR_EQUAL:
13513 return LBP_GREATER_EQUAL;
13514 case ComparisonOperator::LESS_OR_EQUAL:
13515 return LBP_SMALLER_EQUAL;
13516 default:
13517 // WTF? should not happen, this is an error
13518 gcc_unreachable ();
13519
13520 return LBP_EQUAL;
13521 }
13522}
13523
13524/* Parses a ComparisonExpr of given type and LBP. TODO find a way to only
13525 * specify one and have the other looked up - e.g. specify ExprType and
13526 * binding power is looked up? */
13527template <typename ManagedTokenSource>
13528std::unique_ptr<AST::ComparisonExpr>
13529Parser<ManagedTokenSource>::parse_comparison_expr (
13530 const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
13531 AST::ComparisonExpr::ExprType expr_type, ParseRestrictions restrictions)
13532{
13533 // parse RHS (as tok has already been consumed in parse_expression)
13534 std::unique_ptr<AST::Expr> right
13535 = parse_expr (get_lbp_for_comparison_expr (expr_type), AST::AttrVec (),
13536 restrictions);
13537 if (right == nullptr)
13538 return nullptr;
13539
13540 // TODO: check types. actually, do so during semantic analysis
13541 Location locus = left->get_locus ();
13542
13543 return std::unique_ptr<AST::ComparisonExpr> (
13544 new AST::ComparisonExpr (std::move (left), std::move (right), expr_type,
13545 locus));
13546}
13547
13548// Parses a binary equal to expression (with Pratt parsing).
13549template <typename ManagedTokenSource>
13550std::unique_ptr<AST::ComparisonExpr>
13551Parser<ManagedTokenSource>::parse_binary_equal_expr (
13552 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13553 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13554{
13555 // parse RHS (as tok has already been consumed in parse_expression)
13556 std::unique_ptr<AST::Expr> right
13557 = parse_expr (LBP_EQUAL, AST::AttrVec (), restrictions);
13558 if (right == nullptr)
13559 return nullptr;
13560
13561 // TODO: check types. actually, do so during semantic analysis
13562 Location locus = left->get_locus ();
13563
13564 return std::unique_ptr<AST::ComparisonExpr> (
13565 new AST::ComparisonExpr (std::move (left), std::move (right),
13566 ComparisonOperator::EQUAL, locus));
13567}
13568
13569// Parses a binary not equal to expression (with Pratt parsing).
13570template <typename ManagedTokenSource>
13571std::unique_ptr<AST::ComparisonExpr>
13572Parser<ManagedTokenSource>::parse_binary_not_equal_expr (
13573 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13574 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13575{
13576 // parse RHS (as tok has already been consumed in parse_expression)
13577 std::unique_ptr<AST::Expr> right
13578 = parse_expr (LBP_NOT_EQUAL, AST::AttrVec (), restrictions);
13579 if (right == nullptr)
13580 return nullptr;
13581
13582 // TODO: check types. actually, do so during semantic analysis
13583 Location locus = left->get_locus ();
13584
13585 return std::unique_ptr<AST::ComparisonExpr> (
13586 new AST::ComparisonExpr (std::move (left), std::move (right),
13587 ComparisonOperator::NOT_EQUAL, locus));
13588}
13589
13590// Parses a binary greater than expression (with Pratt parsing).
13591template <typename ManagedTokenSource>
13592std::unique_ptr<AST::ComparisonExpr>
13593Parser<ManagedTokenSource>::parse_binary_greater_than_expr (
13594 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13595 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13596{
13597 // parse RHS (as tok has already been consumed in parse_expression)
13598 std::unique_ptr<AST::Expr> right
13599 = parse_expr (LBP_GREATER_THAN, AST::AttrVec (), restrictions);
13600 if (right == nullptr)
13601 return nullptr;
13602
13603 // TODO: check types. actually, do so during semantic analysis
13604 Location locus = left->get_locus ();
13605
13606 return std::unique_ptr<AST::ComparisonExpr> (
13607 new AST::ComparisonExpr (std::move (left), std::move (right),
13608 ComparisonOperator::GREATER_THAN, locus));
13609}
13610
13611// Parses a binary less than expression (with Pratt parsing).
13612template <typename ManagedTokenSource>
13613std::unique_ptr<AST::ComparisonExpr>
13614Parser<ManagedTokenSource>::parse_binary_less_than_expr (
13615 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13616 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13617{
13618 // parse RHS (as tok has already been consumed in parse_expression)
13619 std::unique_ptr<AST::Expr> right
13620 = parse_expr (LBP_SMALLER_THAN, AST::AttrVec (), restrictions);
13621 if (right == nullptr)
13622 return nullptr;
13623
13624 // TODO: check types. actually, do so during semantic analysis
13625 Location locus = left->get_locus ();
13626
13627 return std::unique_ptr<AST::ComparisonExpr> (
13628 new AST::ComparisonExpr (std::move (left), std::move (right),
13629 ComparisonOperator::LESS_THAN, locus));
13630}
13631
13632// Parses a binary greater than or equal to expression (with Pratt parsing).
13633template <typename ManagedTokenSource>
13634std::unique_ptr<AST::ComparisonExpr>
13635Parser<ManagedTokenSource>::parse_binary_greater_equal_expr (
13636 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13637 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13638{
13639 // parse RHS (as tok has already been consumed in parse_expression)
13640 std::unique_ptr<AST::Expr> right
13641 = parse_expr (LBP_GREATER_EQUAL, AST::AttrVec (), restrictions);
13642 if (right == nullptr)
13643 return nullptr;
13644
13645 // TODO: check types. actually, do so during semantic analysis
13646 Location locus = left->get_locus ();
13647
13648 return std::unique_ptr<AST::ComparisonExpr> (
13649 new AST::ComparisonExpr (std::move (left), std::move (right),
13650 ComparisonOperator::GREATER_OR_EQUAL, locus));
13651}
13652
13653// Parses a binary less than or equal to expression (with Pratt parsing).
13654template <typename ManagedTokenSource>
13655std::unique_ptr<AST::ComparisonExpr>
13656Parser<ManagedTokenSource>::parse_binary_less_equal_expr (
13657 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13658 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13659{
13660 // parse RHS (as tok has already been consumed in parse_expression)
13661 std::unique_ptr<AST::Expr> right
13662 = parse_expr (LBP_SMALLER_EQUAL, AST::AttrVec (), restrictions);
13663 if (right == nullptr)
13664 return nullptr;
13665
13666 // TODO: check types. actually, do so during semantic analysis
13667 Location locus = left->get_locus ();
13668
13669 return std::unique_ptr<AST::ComparisonExpr> (
13670 new AST::ComparisonExpr (std::move (left), std::move (right),
13671 ComparisonOperator::LESS_OR_EQUAL, locus));
13672}
13673
13674// Parses a binary lazy boolean or expression (with Pratt parsing).
13675template <typename ManagedTokenSource>
13676std::unique_ptr<AST::LazyBooleanExpr>
13677Parser<ManagedTokenSource>::parse_lazy_or_expr (
13678 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13679 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13680{
13681 // parse RHS (as tok has already been consumed in parse_expression)
13682 std::unique_ptr<AST::Expr> right
13683 = parse_expr (LBP_LOGICAL_OR, AST::AttrVec (), restrictions);
13684 if (right == nullptr)
13685 return nullptr;
13686
13687 // TODO: check types. actually, do so during semantic analysis
13688 Location locus = left->get_locus ();
13689
13690 return std::unique_ptr<AST::LazyBooleanExpr> (
13691 new AST::LazyBooleanExpr (std::move (left), std::move (right),
13692 LazyBooleanOperator::LOGICAL_OR, locus));
13693}
13694
13695// Parses a binary lazy boolean and expression (with Pratt parsing).
13696template <typename ManagedTokenSource>
13697std::unique_ptr<AST::LazyBooleanExpr>
13698Parser<ManagedTokenSource>::parse_lazy_and_expr (
13699 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13700 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13701{
13702 // parse RHS (as tok has already been consumed in parse_expression)
13703 std::unique_ptr<AST::Expr> right
13704 = parse_expr (LBP_LOGICAL_AND, AST::AttrVec (), restrictions);
13705 if (right == nullptr)
13706 return nullptr;
13707
13708 // TODO: check types. actually, do so during semantic analysis
13709 Location locus = left->get_locus ();
13710
13711 return std::unique_ptr<AST::LazyBooleanExpr> (
13712 new AST::LazyBooleanExpr (std::move (left), std::move (right),
13713 LazyBooleanOperator::LOGICAL_AND, locus));
13714}
13715
13716// Parses a pseudo-binary infix type cast expression (with Pratt parsing).
13717template <typename ManagedTokenSource>
13718std::unique_ptr<AST::TypeCastExpr>
13719Parser<ManagedTokenSource>::parse_type_cast_expr (
13720 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> expr_to_cast,
13721 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED,
13722 ParseRestrictions restrictions ATTRIBUTE_UNUSED)
13723{
13724 // parse RHS (as tok has already been consumed in parse_expression)
13725 std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
13726 if (type == nullptr)
13727 return nullptr;
13728 // FIXME: how do I get precedence put in here?
13729
13730 // TODO: check types. actually, do so during semantic analysis
13731 Location locus = expr_to_cast->get_locus ();
13732
13733 return std::unique_ptr<AST::TypeCastExpr> (
13734 new AST::TypeCastExpr (std::move (expr_to_cast), std::move (type), locus));
13735}
13736
13737// Parses a binary assignment expression (with Pratt parsing).
13738template <typename ManagedTokenSource>
13739std::unique_ptr<AST::AssignmentExpr>
13740Parser<ManagedTokenSource>::parse_assig_expr (
13741 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13742 AST::AttrVec outer_attrs, ParseRestrictions restrictions)
13743{
13744 // parse RHS (as tok has already been consumed in parse_expression)
13745 std::unique_ptr<AST::Expr> right
13746 = parse_expr (LBP_ASSIG - 1, AST::AttrVec (), restrictions);
13747 if (right == nullptr)
13748 return nullptr;
13749 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13750
13751 // TODO: check types. actually, do so during semantic analysis
13752 Location locus = left->get_locus ();
13753
13754 return std::unique_ptr<AST::AssignmentExpr> (
13755 new AST::AssignmentExpr (std::move (left), std::move (right),
13756 std::move (outer_attrs), locus));
13757}
13758
13759/* Returns the left binding power for the given CompoundAssignmentExpr type.
13760 * TODO make constexpr? Would that even do anything useful? */
13761inline binding_powers
13762get_lbp_for_compound_assignment_expr (
13763 AST::CompoundAssignmentExpr::ExprType expr_type)
13764{
13765 switch (expr_type)
13766 {
13767 case CompoundAssignmentOperator::ADD:
13768 return LBP_PLUS;
13769 case CompoundAssignmentOperator::SUBTRACT:
13770 return LBP_MINUS;
13771 case CompoundAssignmentOperator::MULTIPLY:
13772 return LBP_MUL;
13773 case CompoundAssignmentOperator::DIVIDE:
13774 return LBP_DIV;
13775 case CompoundAssignmentOperator::MODULUS:
13776 return LBP_MOD;
13777 case CompoundAssignmentOperator::BITWISE_AND:
13778 return LBP_AMP;
13779 case CompoundAssignmentOperator::BITWISE_OR:
13780 return LBP_PIPE;
13781 case CompoundAssignmentOperator::BITWISE_XOR:
13782 return LBP_CARET;
13783 case CompoundAssignmentOperator::LEFT_SHIFT:
13784 return LBP_L_SHIFT;
13785 case CompoundAssignmentOperator::RIGHT_SHIFT:
13786 return LBP_R_SHIFT;
13787 default:
13788 // WTF? should not happen, this is an error
13789 gcc_unreachable ();
13790
13791 return LBP_PLUS;
13792 }
13793}
13794
13795// Parses a compound assignment expression (with Pratt parsing).
13796template <typename ManagedTokenSource>
13797std::unique_ptr<AST::CompoundAssignmentExpr>
13798Parser<ManagedTokenSource>::parse_compound_assignment_expr (
13799 const_TokenPtr, std::unique_ptr<AST::Expr> left, AST::AttrVec,
13800 AST::CompoundAssignmentExpr::ExprType expr_type,
13801 ParseRestrictions restrictions)
13802{
13803 // parse RHS (as tok has already been consumed in parse_expression)
13804 std::unique_ptr<AST::Expr> right
13805 = parse_expr (get_lbp_for_compound_assignment_expr (expr_type) - 1,
13806 AST::AttrVec (), restrictions);
13807 if (right == nullptr)
13808 return nullptr;
13809 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13810
13811 // TODO: check types. actually, do so during semantic analysis
13812 Location locus = left->get_locus ();
13813
13814 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13815 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13816 expr_type, locus));
13817}
13818
13819// Parses a binary add-assignment expression (with Pratt parsing).
13820template <typename ManagedTokenSource>
13821std::unique_ptr<AST::CompoundAssignmentExpr>
13822Parser<ManagedTokenSource>::parse_plus_assig_expr (
13823 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13824 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13825{
13826 // parse RHS (as tok has already been consumed in parse_expression)
13827 std::unique_ptr<AST::Expr> right
13828 = parse_expr (LBP_PLUS_ASSIG - 1, AST::AttrVec (), restrictions);
13829 if (right == nullptr)
13830 return nullptr;
13831 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13832
13833 // TODO: check types. actually, do so during semantic analysis
13834 Location locus = left->get_locus ();
13835
13836 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13837 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13838 CompoundAssignmentOperator::ADD, locus));
13839}
13840
13841// Parses a binary minus-assignment expression (with Pratt parsing).
13842template <typename ManagedTokenSource>
13843std::unique_ptr<AST::CompoundAssignmentExpr>
13844Parser<ManagedTokenSource>::parse_minus_assig_expr (
13845 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13846 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13847{
13848 // parse RHS (as tok has already been consumed in parse_expression)
13849 std::unique_ptr<AST::Expr> right
13850 = parse_expr (LBP_MINUS_ASSIG - 1, AST::AttrVec (), restrictions);
13851 if (right == nullptr)
13852 return nullptr;
13853 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13854
13855 // TODO: check types. actually, do so during semantic analysis
13856 Location locus = left->get_locus ();
13857
13858 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13859 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13860 CompoundAssignmentOperator::SUBTRACT,
13861 locus));
13862}
13863
13864// Parses a binary multiplication-assignment expression (with Pratt parsing).
13865template <typename ManagedTokenSource>
13866std::unique_ptr<AST::CompoundAssignmentExpr>
13867Parser<ManagedTokenSource>::parse_mult_assig_expr (
13868 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13869 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13870{
13871 // parse RHS (as tok has already been consumed in parse_expression)
13872 std::unique_ptr<AST::Expr> right
13873 = parse_expr (LBP_MULT_ASSIG - 1, AST::AttrVec (), restrictions);
13874 if (right == nullptr)
13875 return nullptr;
13876 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13877
13878 // TODO: check types. actually, do so during semantic analysis
13879 Location locus = left->get_locus ();
13880
13881 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13882 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13883 CompoundAssignmentOperator::MULTIPLY,
13884 locus));
13885}
13886
13887// Parses a binary division-assignment expression (with Pratt parsing).
13888template <typename ManagedTokenSource>
13889std::unique_ptr<AST::CompoundAssignmentExpr>
13890Parser<ManagedTokenSource>::parse_div_assig_expr (
13891 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13892 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13893{
13894 // parse RHS (as tok has already been consumed in parse_expression)
13895 std::unique_ptr<AST::Expr> right
13896 = parse_expr (LBP_DIV_ASSIG - 1, AST::AttrVec (), restrictions);
13897 if (right == nullptr)
13898 return nullptr;
13899 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13900
13901 // TODO: check types. actually, do so during semantic analysis
13902 Location locus = left->get_locus ();
13903
13904 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13905 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13906 CompoundAssignmentOperator::DIVIDE,
13907 locus));
13908}
13909
13910// Parses a binary modulo-assignment expression (with Pratt parsing).
13911template <typename ManagedTokenSource>
13912std::unique_ptr<AST::CompoundAssignmentExpr>
13913Parser<ManagedTokenSource>::parse_mod_assig_expr (
13914 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13915 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13916{
13917 // parse RHS (as tok has already been consumed in parse_expression)
13918 std::unique_ptr<AST::Expr> right
13919 = parse_expr (LBP_MOD_ASSIG - 1, AST::AttrVec (), restrictions);
13920 if (right == nullptr)
13921 return nullptr;
13922 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13923
13924 // TODO: check types. actually, do so during semantic analysis
13925 Location locus = left->get_locus ();
13926
13927 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13928 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13929 CompoundAssignmentOperator::MODULUS,
13930 locus));
13931}
13932
13933// Parses a binary and-assignment expression (with Pratt parsing).
13934template <typename ManagedTokenSource>
13935std::unique_ptr<AST::CompoundAssignmentExpr>
13936Parser<ManagedTokenSource>::parse_and_assig_expr (
13937 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13938 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13939{
13940 // parse RHS (as tok has already been consumed in parse_expression)
13941 std::unique_ptr<AST::Expr> right
13942 = parse_expr (LBP_AMP_ASSIG - 1, AST::AttrVec (), restrictions);
13943 if (right == nullptr)
13944 return nullptr;
13945 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13946
13947 // TODO: check types. actually, do so during semantic analysis
13948 Location locus = left->get_locus ();
13949
13950 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13951 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13952 CompoundAssignmentOperator::BITWISE_AND,
13953 locus));
13954}
13955
13956// Parses a binary or-assignment expression (with Pratt parsing).
13957template <typename ManagedTokenSource>
13958std::unique_ptr<AST::CompoundAssignmentExpr>
13959Parser<ManagedTokenSource>::parse_or_assig_expr (
13960 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13961 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13962{
13963 // parse RHS (as tok has already been consumed in parse_expression)
13964 std::unique_ptr<AST::Expr> right
13965 = parse_expr (LBP_PIPE_ASSIG - 1, AST::AttrVec (), restrictions);
13966 if (right == nullptr)
13967 return nullptr;
13968 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13969
13970 // TODO: check types. actually, do so during semantic analysis
13971 Location locus = left->get_locus ();
13972
13973 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13974 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13975 CompoundAssignmentOperator::BITWISE_OR,
13976 locus));
13977}
13978
13979// Parses a binary xor-assignment expression (with Pratt parsing).
13980template <typename ManagedTokenSource>
13981std::unique_ptr<AST::CompoundAssignmentExpr>
13982Parser<ManagedTokenSource>::parse_xor_assig_expr (
13983 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
13984 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
13985{
13986 // parse RHS (as tok has already been consumed in parse_expression)
13987 std::unique_ptr<AST::Expr> right
13988 = parse_expr (LBP_CARET_ASSIG - 1, AST::AttrVec (), restrictions);
13989 if (right == nullptr)
13990 return nullptr;
13991 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13992
13993 // TODO: check types. actually, do so during semantic analysis
13994 Location locus = left->get_locus ();
13995
13996 return std::unique_ptr<AST::CompoundAssignmentExpr> (
13997 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
13998 CompoundAssignmentOperator::BITWISE_XOR,
13999 locus));
14000}
14001
14002// Parses a binary left shift-assignment expression (with Pratt parsing).
14003template <typename ManagedTokenSource>
14004std::unique_ptr<AST::CompoundAssignmentExpr>
14005Parser<ManagedTokenSource>::parse_left_shift_assig_expr (
14006 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
14007 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
14008{
14009 // parse RHS (as tok has already been consumed in parse_expression)
14010 std::unique_ptr<AST::Expr> right
14011 = parse_expr (LBP_L_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
14012 if (right == nullptr)
14013 return nullptr;
14014 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
14015
14016 // TODO: check types. actually, do so during semantic analysis
14017 Location locus = left->get_locus ();
14018
14019 return std::unique_ptr<AST::CompoundAssignmentExpr> (
14020 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
14021 CompoundAssignmentOperator::LEFT_SHIFT,
14022 locus));
14023}
14024
14025// Parses a binary right shift-assignment expression (with Pratt parsing).
14026template <typename ManagedTokenSource>
14027std::unique_ptr<AST::CompoundAssignmentExpr>
14028Parser<ManagedTokenSource>::parse_right_shift_assig_expr (
14029 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
14030 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
14031{
14032 // parse RHS (as tok has already been consumed in parse_expression)
14033 std::unique_ptr<AST::Expr> right
14034 = parse_expr (LBP_R_SHIFT_ASSIG - 1, AST::AttrVec (), restrictions);
14035 if (right == nullptr)
14036 return nullptr;
14037 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
14038
14039 // TODO: check types. actually, do so during semantic analysis
14040 Location locus = left->get_locus ();
14041
14042 return std::unique_ptr<AST::CompoundAssignmentExpr> (
14043 new AST::CompoundAssignmentExpr (std::move (left), std::move (right),
14044 CompoundAssignmentOperator::RIGHT_SHIFT,
14045 locus));
14046}
14047
14048// Parses a postfix unary await expression (with Pratt parsing).
14049template <typename ManagedTokenSource>
14050std::unique_ptr<AST::AwaitExpr>
14051Parser<ManagedTokenSource>::parse_await_expr (
14052 const_TokenPtr tok, std::unique_ptr<AST::Expr> expr_to_await,
14053 AST::AttrVec outer_attrs)
14054{
14055 /* skip "await" identifier (as "." has already been consumed in
14056 * parse_expression) this assumes that the identifier was already identified
14057 * as await */
14058 if (!skip_token (IDENTIFIER))
14059 {
14060 Error error (tok->get_locus (), "failed to skip %<await%> in await expr "
14061 "- this is probably a deep issue");
14062 add_error (std::move (error));
14063
14064 // skip somewhere?
14065 return nullptr;
14066 }
14067
14068 // TODO: check inside async block in semantic analysis
14069 Location locus = expr_to_await->get_locus ();
14070
14071 return std::unique_ptr<AST::AwaitExpr> (
14072 new AST::AwaitExpr (std::move (expr_to_await), std::move (outer_attrs),
14073 locus));
14074}
14075
14076/* Parses an exclusive range ('..') in left denotation position (i.e.
14077 * RangeFromExpr or RangeFromToExpr). */
14078template <typename ManagedTokenSource>
14079std::unique_ptr<AST::RangeExpr>
14080Parser<ManagedTokenSource>::parse_led_range_exclusive_expr (
14081 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
14082 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
14083{
14084 // FIXME: this probably parses expressions accidently or whatever
14085 // try parsing RHS (as tok has already been consumed in parse_expression)
14086 // Can be nullptr, in which case it is a RangeFromExpr, otherwise a
14087 // RangeFromToExpr.
14088 restrictions.expr_can_be_null = true;
14089 std::unique_ptr<AST::Expr> right
14090 = parse_expr (LBP_DOT_DOT, AST::AttrVec (), restrictions);
14091
14092 Location locus = left->get_locus ();
14093
14094 if (right == nullptr)
14095 {
14096 // range from expr
14097 return std::unique_ptr<AST::RangeFromExpr> (
14098 new AST::RangeFromExpr (std::move (left), locus));
14099 }
14100 else
14101 {
14102 return std::unique_ptr<AST::RangeFromToExpr> (
14103 new AST::RangeFromToExpr (std::move (left), std::move (right), locus));
14104 }
14105 // FIXME: make non-associative
14106}
14107
14108/* Parses an exclusive range ('..') in null denotation position (i.e.
14109 * RangeToExpr or RangeFullExpr). */
14110template <typename ManagedTokenSource>
14111std::unique_ptr<AST::RangeExpr>
14112Parser<ManagedTokenSource>::parse_nud_range_exclusive_expr (
14113 const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
14114{
14115 // FIXME: this probably parses expressions accidently or whatever
14116 // try parsing RHS (as tok has already been consumed in parse_expression)
14117 std::unique_ptr<AST::Expr> right = parse_expr (LBP_DOT_DOT, AST::AttrVec ());
14118
14119 Location locus = tok->get_locus ();
14120
14121 if (right == nullptr)
14122 {
14123 // range from expr
14124 return std::unique_ptr<AST::RangeFullExpr> (
14125 new AST::RangeFullExpr (locus));
14126 }
14127 else
14128 {
14129 return std::unique_ptr<AST::RangeToExpr> (
14130 new AST::RangeToExpr (std::move (right), locus));
14131 }
14132 // FIXME: make non-associative
14133}
14134
14135// Parses a full binary range inclusive expression.
14136template <typename ManagedTokenSource>
14137std::unique_ptr<AST::RangeFromToInclExpr>
14138Parser<ManagedTokenSource>::parse_range_inclusive_expr (
14139 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> left,
14140 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED, ParseRestrictions restrictions)
14141{
14142 // parse RHS (as tok has already been consumed in parse_expression)
14143 std::unique_ptr<AST::Expr> right
14144 = parse_expr (LBP_DOT_DOT_EQ, AST::AttrVec (), restrictions);
14145 if (right == nullptr)
14146 return nullptr;
14147 // FIXME: make non-associative
14148
14149 // TODO: check types. actually, do so during semantic analysis
14150 Location locus = left->get_locus ();
14151
14152 return std::unique_ptr<AST::RangeFromToInclExpr> (
14153 new AST::RangeFromToInclExpr (std::move (left), std::move (right), locus));
14154}
14155
14156// Parses an inclusive range-to prefix unary expression.
14157template <typename ManagedTokenSource>
14158std::unique_ptr<AST::RangeToInclExpr>
14159Parser<ManagedTokenSource>::parse_range_to_inclusive_expr (
14160 const_TokenPtr tok, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED)
14161{
14162 // parse RHS (as tok has already been consumed in parse_expression)
14163 std::unique_ptr<AST::Expr> right = parse_expr (LBP_DOT_DOT_EQ);
14164 if (right == nullptr)
14165 return nullptr;
14166 // FIXME: make non-associative
14167
14168 // TODO: check types. actually, do so during semantic analysis
14169
14170 return std::unique_ptr<AST::RangeToInclExpr> (
14171 new AST::RangeToInclExpr (std::move (right), tok->get_locus ()));
14172}
14173
14174// Parses a pseudo-binary infix tuple index expression.
14175template <typename ManagedTokenSource>
14176std::unique_ptr<AST::TupleIndexExpr>
14177Parser<ManagedTokenSource>::parse_tuple_index_expr (
14178 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> tuple_expr,
14179 AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
14180{
14181 // parse int literal (as token already skipped)
14182 const_TokenPtr index_tok = expect_token (INT_LITERAL);
14183 if (index_tok == nullptr)
14184 {
14185 return nullptr;
14186 }
14187 std::string index = index_tok->get_str ();
14188
14189 // convert to integer
14190 if (!index_tok->is_pure_decimal ())
14191 {
14192 Error error (index_tok->get_locus (),
14193 "tuple index should be a pure decimal literal");
14194 add_error (std::move (error));
14195 }
14196 int index_int = atoi (index.c_str ());
14197
14198 Location locus = tuple_expr->get_locus ();
14199
14200 return std::unique_ptr<AST::TupleIndexExpr> (
14201 new AST::TupleIndexExpr (std::move (tuple_expr), index_int,
14202 std::move (outer_attrs), locus));
14203}
14204
14205// Parses a pseudo-binary infix array (or slice) index expression.
14206template <typename ManagedTokenSource>
14207std::unique_ptr<AST::ArrayIndexExpr>
14208Parser<ManagedTokenSource>::parse_index_expr (
14209 const_TokenPtr, std::unique_ptr<AST::Expr> array_expr,
14210 AST::AttrVec outer_attrs, ParseRestrictions)
14211{
14212 // parse RHS (as tok has already been consumed in parse_expression)
14213 /*std::unique_ptr<AST::Expr> index_expr
14214 = parse_expr (LBP_ARRAY_REF, AST::AttrVec (),
14215 restrictions);*/
14216 // TODO: conceptually, should treat [] as brackets, so just parse all expr
14217 std::unique_ptr<AST::Expr> index_expr = parse_expr ();
14218 if (index_expr == nullptr)
14219 return nullptr;
14220
14221 // skip ']' at end of array
14222 if (!skip_token (RIGHT_SQUARE))
14223 {
14224 // skip somewhere?
14225 return nullptr;
14226 }
14227
14228 // TODO: check types. actually, do so during semantic analysis
14229 Location locus = array_expr->get_locus ();
14230
14231 return std::unique_ptr<AST::ArrayIndexExpr> (
14232 new AST::ArrayIndexExpr (std::move (array_expr), std::move (index_expr),
14233 std::move (outer_attrs), locus));
14234}
14235
14236// Parses a pseudo-binary infix struct field access expression.
14237template <typename ManagedTokenSource>
14238std::unique_ptr<AST::FieldAccessExpr>
14239Parser<ManagedTokenSource>::parse_field_access_expr (
14240 const_TokenPtr tok ATTRIBUTE_UNUSED, std::unique_ptr<AST::Expr> struct_expr,
14241 AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
14242{
14243 /* get field name identifier (assume that this is a field access expr and
14244 * not await, for instance) */
14245 const_TokenPtr ident_tok = expect_token (IDENTIFIER);
14246 if (ident_tok == nullptr)
14247 return nullptr;
14248
14249 Identifier ident = ident_tok->get_str ();
14250
14251 Location locus = struct_expr->get_locus ();
14252
14253 // TODO: check types. actually, do so during semantic analysis
14254 return std::unique_ptr<AST::FieldAccessExpr> (
14255 new AST::FieldAccessExpr (std::move (struct_expr), std::move (ident),
14256 std::move (outer_attrs), locus));
14257}
14258
14259// Parses a pseudo-binary infix method call expression.
14260template <typename ManagedTokenSource>
14261std::unique_ptr<AST::MethodCallExpr>
14262Parser<ManagedTokenSource>::parse_method_call_expr (
14263 const_TokenPtr tok, std::unique_ptr<AST::Expr> receiver_expr,
14264 AST::AttrVec outer_attrs, ParseRestrictions)
14265{
14266 // parse path expr segment
14267 AST::PathExprSegment segment = parse_path_expr_segment ();
14268 if (segment.is_error ())
14269 {
14270 Error error (tok->get_locus (),
14271 "failed to parse path expr segment of method call expr");
14272 add_error (std::move (error));
14273
14274 return nullptr;
14275 }
14276
14277 // skip left parentheses
14278 if (!skip_token (LEFT_PAREN))
14279 {
14280 return nullptr;
14281 }
14282
14283 // parse method params (if they exist)
14284 std::vector<std::unique_ptr<AST::Expr>> params;
14285
14286 const_TokenPtr t = lexer.peek_token ();
14287 while (t->get_id () != RIGHT_PAREN)
14288 {
14289 std::unique_ptr<AST::Expr> param = parse_expr ();
14290 if (param == nullptr)
14291 {
14292 Error error (t->get_locus (),
14293 "failed to parse method param in method call");
14294 add_error (std::move (error));
14295
14296 return nullptr;
14297 }
14298 params.push_back (std::move (param));
14299
14300 if (lexer.peek_token ()->get_id () != COMMA)
14301 break;
14302
14303 lexer.skip_token ();
14304 t = lexer.peek_token ();
14305 }
14306
14307 // skip right paren
14308 if (!skip_token (RIGHT_PAREN))
14309 {
14310 return nullptr;
14311 }
14312
14313 // TODO: check types. actually do so in semantic analysis pass.
14314 Location locus = receiver_expr->get_locus ();
14315
14316 return std::unique_ptr<AST::MethodCallExpr> (
14317 new AST::MethodCallExpr (std::move (receiver_expr), std::move (segment),
14318 std::move (params), std::move (outer_attrs),
14319 locus));
14320}
14321
14322// Parses a pseudo-binary infix function call expression.
14323template <typename ManagedTokenSource>
14324std::unique_ptr<AST::CallExpr>
14325Parser<ManagedTokenSource>::parse_function_call_expr (
14326 const_TokenPtr, std::unique_ptr<AST::Expr> function_expr,
14327 AST::AttrVec outer_attrs, ParseRestrictions)
14328{
14329 // parse function params (if they exist)
14330 std::vector<std::unique_ptr<AST::Expr>> params;
14331
14332 const_TokenPtr t = lexer.peek_token ();
14333 while (t->get_id () != RIGHT_PAREN)
14334 {
14335 std::unique_ptr<AST::Expr> param = parse_expr ();
14336 if (param == nullptr)
14337 {
14338 Error error (t->get_locus (),
14339 "failed to parse function param in function call");
14340 add_error (std::move (error));
14341
14342 return nullptr;
14343 }
14344 params.push_back (std::move (param));
14345
14346 if (lexer.peek_token ()->get_id () != COMMA)
14347 break;
14348
14349 lexer.skip_token ();
14350 t = lexer.peek_token ();
14351 }
14352
14353 // skip ')' at end of param list
14354 if (!skip_token (RIGHT_PAREN))
14355 {
14356 // skip somewhere?
14357 return nullptr;
14358 }
14359
14360 // TODO: check types. actually, do so during semantic analysis
14361 Location locus = function_expr->get_locus ();
14362
14363 return std::unique_ptr<AST::CallExpr> (
14364 new AST::CallExpr (std::move (function_expr), std::move (params),
14365 std::move (outer_attrs), locus));
14366}
14367
14368/* Parses a macro invocation with a path in expression already parsed (but not
14369 * '!' token). */
14370template <typename ManagedTokenSource>
14371std::unique_ptr<AST::MacroInvocation>
14372Parser<ManagedTokenSource>::parse_macro_invocation_partial (
14373 AST::PathInExpression path, AST::AttrVec outer_attrs,
14374 ParseRestrictions restrictions)
14375{
14376 // macro invocation
14377 if (!skip_token (EXCLAM))
14378 {
14379 return nullptr;
14380 }
14381
14382 // convert PathInExpression to SimplePath - if this isn't possible, error
14383 AST::SimplePath converted_path = path.as_simple_path ();
14384 if (converted_path.is_empty ())
14385 {
14386 Error error (lexer.peek_token ()->get_locus (),
14387 "failed to parse simple path in macro invocation");
14388 add_error (std::move (error));
14389
14390 return nullptr;
14391 }
14392
14393 AST::DelimTokenTree tok_tree = parse_delim_token_tree ();
14394
14395 rust_debug ("successfully parsed macro invocation (via partial)");
14396
14397 Location macro_locus = converted_path.get_locus ();
14398
14399 return std::unique_ptr<AST::MacroInvocation> (new AST::MacroInvocation (
14400 AST::MacroInvocData (std::move (converted_path), std::move (tok_tree)),
14401 std::move (outer_attrs), macro_locus, restrictions.expr_can_be_stmt));
14402}
14403
14404/* Parses a struct expr struct with a path in expression already parsed (but
14405 * not
14406 * '{' token). */
14407template <typename ManagedTokenSource>
14408std::unique_ptr<AST::StructExprStruct>
14409Parser<ManagedTokenSource>::parse_struct_expr_struct_partial (
14410 AST::PathInExpression path, AST::AttrVec outer_attrs)
14411{
14412 // assume struct expr struct (as struct-enum disambiguation requires name
14413 // lookup) again, make statement if final ';'
14414 if (!skip_token (LEFT_CURLY))
14415 {
14416 return nullptr;
14417 }
14418
14419 // parse inner attributes
14420 AST::AttrVec inner_attrs = parse_inner_attributes ();
14421
14422 // branch based on next token
14423 const_TokenPtr t = lexer.peek_token ();
14424 Location path_locus = path.get_locus ();
14425 switch (t->get_id ())
14426 {
14427 case RIGHT_CURLY:
14428 // struct with no body
14429 lexer.skip_token ();
14430
14431 return std::unique_ptr<AST::StructExprStruct> (
14432 new AST::StructExprStruct (std::move (path), std::move (inner_attrs),
14433 std::move (outer_attrs), path_locus));
14434 case DOT_DOT:
14435 /* technically this would give a struct base-only struct, but this
14436 * algorithm should work too. As such, AST type not happening. */
14437 case IDENTIFIER:
14438 case INT_LITERAL: {
14439 // struct with struct expr fields
14440
14441 // parse struct expr fields
14442 std::vector<std::unique_ptr<AST::StructExprField>> fields;
14443
14444 while (t->get_id () != RIGHT_CURLY && t->get_id () != DOT_DOT)
14445 {
14446 std::unique_ptr<AST::StructExprField> field
14447 = parse_struct_expr_field ();
14448 if (field == nullptr)
14449 {
14450 Error error (t->get_locus (),
14451 "failed to parse struct (or enum) expr field");
14452 add_error (std::move (error));
14453
14454 return nullptr;
14455 }
14456
14457 // DEBUG:
14458 rust_debug ("struct/enum expr field validated to not be null");
14459
14460 fields.push_back (std::move (field));
14461
14462 // DEBUG:
14463 rust_debug ("struct/enum expr field pushed back");
14464
14465 if (lexer.peek_token ()->get_id () != COMMA)
14466 {
14467 // DEBUG:
14468 rust_debug ("lack of comma detected in struct/enum expr "
14469 "fields - break");
14470 break;
14471 }
14472 lexer.skip_token ();
14473
14474 // DEBUG:
14475 rust_debug ("struct/enum expr fields comma skipped ");
14476
14477 t = lexer.peek_token ();
14478 }
14479
14480 // DEBUG:
14481 rust_debug ("struct/enum expr about to parse struct base ");
14482
14483 // parse struct base if it exists
14484 AST::StructBase struct_base = AST::StructBase::error ();
14485 if (lexer.peek_token ()->get_id () == DOT_DOT)
14486 {
14487 Location dot_dot_location = lexer.peek_token ()->get_locus ();
14488 lexer.skip_token ();
14489
14490 // parse required struct base expr
14491 std::unique_ptr<AST::Expr> base_expr = parse_expr ();
14492 if (base_expr == nullptr)
14493 {
14494 Error error (lexer.peek_token ()->get_locus (),
14495 "failed to parse struct base expression in struct "
14496 "expression");
14497 add_error (std::move (error));
14498
14499 return nullptr;
14500 }
14501
14502 // DEBUG:
14503 rust_debug ("struct/enum expr - parsed and validated base expr");
14504
14505 struct_base
14506 = AST::StructBase (std::move (base_expr), dot_dot_location);
14507
14508 // DEBUG:
14509 rust_debug ("assigned struct base to new struct base ");
14510 }
14511
14512 if (!skip_token (RIGHT_CURLY))
14513 {
14514 return nullptr;
14515 }
14516
14517 // DEBUG:
14518 rust_debug (
14519 "struct/enum expr skipped right curly - done and ready to return");
14520
14521 return std::unique_ptr<AST::StructExprStructFields> (
14522 new AST::StructExprStructFields (std::move (path), std::move (fields),
14523 path_locus, std::move (struct_base),
14524 std::move (inner_attrs),
14525 std::move (outer_attrs)));
14526 }
14527 default:
14528 add_error (
14529 Error (t->get_locus (),
14530 "unrecognised token %qs in struct (or enum) expression - "
14531 "expected %<}%>, identifier, integer literal, or %<..%>",
14532 t->get_token_description ()));
14533
14534 return nullptr;
14535 }
14536}
14537
14538/* Parses a struct expr tuple with a path in expression already parsed (but
14539 * not
14540 * '(' token).
14541 * FIXME: this currently outputs a call expr, as they cannot be disambiguated.
14542 * A better solution would be to just get this to call that function directly.
14543 * */
14544template <typename ManagedTokenSource>
14545std::unique_ptr<AST::CallExpr>
14546Parser<ManagedTokenSource>::parse_struct_expr_tuple_partial (
14547 AST::PathInExpression path, AST::AttrVec outer_attrs)
14548{
14549 if (!skip_token (LEFT_PAREN))
14550 {
14551 return nullptr;
14552 }
14553
14554 AST::AttrVec inner_attrs = parse_inner_attributes ();
14555
14556 std::vector<std::unique_ptr<AST::Expr>> exprs;
14557
14558 const_TokenPtr t = lexer.peek_token ();
14559 while (t->get_id () != RIGHT_PAREN)
14560 {
14561 // parse expression (required)
14562 std::unique_ptr<AST::Expr> expr = parse_expr ();
14563 if (expr == nullptr)
14564 {
14565 Error error (t->get_locus (), "failed to parse expression in "
14566 "struct (or enum) expression tuple");
14567 add_error (std::move (error));
14568
14569 return nullptr;
14570 }
14571 exprs.push_back (std::move (expr));
14572
14573 if (lexer.peek_token ()->get_id () != COMMA)
14574 break;
14575
14576 lexer.skip_token ();
14577
14578 t = lexer.peek_token ();
14579 }
14580
14581 if (!skip_token (RIGHT_PAREN))
14582 {
14583 return nullptr;
14584 }
14585
14586 Location path_locus = path.get_locus ();
14587
14588 auto pathExpr = std::unique_ptr<AST::PathInExpression> (
14589 new AST::PathInExpression (std::move (path)));
14590
14591 return std::unique_ptr<AST::CallExpr> (
14592 new AST::CallExpr (std::move (pathExpr), std::move (exprs),
14593 std::move (outer_attrs), path_locus));
14594}
14595
14596/* Parses a path in expression with the first token passed as a parameter (as
14597 * it is skipped in token stream). Note that this only parses segment-first
14598 * paths, not global ones. */
14599template <typename ManagedTokenSource>
14600AST::PathInExpression
14601Parser<ManagedTokenSource>::parse_path_in_expression_pratt (const_TokenPtr tok)
14602{
14603 // HACK-y way of making up for pratt-parsing consuming first token
14604
14605 // DEBUG
14606 rust_debug ("current peek token when starting path pratt parse: '%s'",
14607 lexer.peek_token ()->get_token_description ());
14608
14609 // create segment vector
14610 std::vector<AST::PathExprSegment> segments;
14611
14612 std::string initial_str;
14613
14614 switch (tok->get_id ())
14615 {
14616 case IDENTIFIER:
14617 initial_str = tok->get_str ();
14618 break;
14619 case SUPER:
14620 initial_str = "super";
14621 break;
14622 case SELF:
14623 initial_str = "self";
14624 break;
14625 case SELF_ALIAS:
14626 initial_str = "Self";
14627 break;
14628 case CRATE:
14629 initial_str = "crate";
14630 break;
14631 case DOLLAR_SIGN:
14632 if (lexer.peek_token ()->get_id () == CRATE)
14633 {
14634 initial_str = "$crate";
14635 break;
14636 }
14637 gcc_fallthrough ();
14638 default:
14639 add_error (Error (tok->get_locus (),
14640 "unrecognised token %qs in path in expression",
14641 tok->get_token_description ()));
14642
14643 return AST::PathInExpression::create_error ();
14644 }
14645
14646 // parse required initial segment
14647 AST::PathExprSegment initial_segment (initial_str, tok->get_locus ());
14648 // parse generic args (and turbofish), if they exist
14649 /* use lookahead to determine if they actually exist (don't want to
14650 * accidently parse over next ident segment) */
14651 if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
14652 && lexer.peek_token (1)->get_id () == LEFT_ANGLE)
14653 {
14654 // skip scope resolution
14655 lexer.skip_token ();
14656
14657 AST::GenericArgs generic_args = parse_path_generic_args ();
14658
14659 initial_segment
14660 = AST::PathExprSegment (AST::PathIdentSegment (initial_str,
14661 tok->get_locus ()),
14662 tok->get_locus (), std::move (generic_args));
14663 }
14664 if (initial_segment.is_error ())
14665 {
14666 // skip after somewhere?
14667 // don't necessarily throw error but yeah
14668
14669 // DEBUG
14670 rust_debug ("initial segment is error - returning null");
14671
14672 return AST::PathInExpression::create_error ();
14673 }
14674 segments.push_back (std::move (initial_segment));
14675
14676 // parse optional segments (as long as scope resolution operator exists)
14677 const_TokenPtr t = lexer.peek_token ();
14678 while (t->get_id () == SCOPE_RESOLUTION)
14679 {
14680 // skip scope resolution operator
14681 lexer.skip_token ();
14682
14683 // parse the actual segment - it is an error if it doesn't exist now
14684 AST::PathExprSegment segment = parse_path_expr_segment ();
14685 if (segment.is_error ())
14686 {
14687 // skip after somewhere?
14688 Error error (t->get_locus (),
14689 "could not parse path expression segment");
14690 add_error (std::move (error));
14691
14692 return AST::PathInExpression::create_error ();
14693 }
14694
14695 segments.push_back (std::move (segment));
14696
14697 t = lexer.peek_token ();
14698 }
14699
14700 // DEBUG:
14701 rust_debug (
14702 "current token (just about to return path to null denotation): '%s'",
14703 lexer.peek_token ()->get_token_description ());
14704
14705 return AST::PathInExpression (std::move (segments), {}, tok->get_locus (),
14706 false);
14707}
14708
14709// Parses a closure expression with pratt parsing (from null denotation).
14710template <typename ManagedTokenSource>
14711std::unique_ptr<AST::ClosureExpr>
14712Parser<ManagedTokenSource>::parse_closure_expr_pratt (const_TokenPtr tok,
14713 AST::AttrVec outer_attrs)
14714{
14715 // TODO: does this need pratt parsing (for precedence)? probably not, but
14716 // idk
14717 Location locus = tok->get_locus ();
14718 bool has_move = false;
14719 if (tok->get_id () == MOVE)
14720 {
14721 has_move = true;
14722 tok = lexer.peek_token ();
14723 lexer.skip_token ();
14724 // skip token and reassign
14725 }
14726
14727 // handle parameter list
14728 std::vector<AST::ClosureParam> params;
14729
14730 switch (tok->get_id ())
14731 {
14732 case OR:
14733 // no parameters, don't skip token
14734 break;
14735 case PIPE: {
14736 // actually may have parameters
14737 // don't skip token
14738 const_TokenPtr t = lexer.peek_token ();
14739 while (t->get_id () != PIPE)
14740 {
14741 AST::ClosureParam param = parse_closure_param ();
14742 if (param.is_error ())
14743 {
14744 // TODO is this really an error?
14745 Error error (t->get_locus (), "could not parse closure param");
14746 add_error (std::move (error));
14747
14748 return nullptr;
14749 }
14750 params.push_back (std::move (param));
14751
14752 if (lexer.peek_token ()->get_id () != COMMA)
14753 {
14754 // not an error but means param list is done
14755 break;
14756 }
14757 // skip comma
14758 lexer.skip_token ();
14759
14760 t = lexer.peek_token ();
14761 }
14762
14763 if (!skip_token (PIPE))
14764 {
14765 return nullptr;
14766 }
14767 break;
14768 }
14769 default:
14770 add_error (Error (tok->get_locus (),
14771 "unexpected token %qs in closure expression - expected "
14772 "%<|%> or %<||%>",
14773 tok->get_token_description ()));
14774
14775 // skip somewhere?
14776 return nullptr;
14777 }
14778
14779 // again branch based on next token
14780 tok = lexer.peek_token ();
14781 if (tok->get_id () == RETURN_TYPE)
14782 {
14783 // must be return type closure with block expr
14784
14785 // skip "return type" token
14786 lexer.skip_token ();
14787
14788 // parse actual type, which is required
14789 std::unique_ptr<AST::TypeNoBounds> type = parse_type_no_bounds ();
14790 if (type == nullptr)
14791 {
14792 // error
14793 Error error (tok->get_locus (), "failed to parse type for closure");
14794 add_error (std::move (error));
14795
14796 // skip somewhere?
14797 return nullptr;
14798 }
14799
14800 // parse block expr, which is required
14801 std::unique_ptr<AST::BlockExpr> block = parse_block_expr ();
14802 if (block == nullptr)
14803 {
14804 // error
14805 Error error (lexer.peek_token ()->get_locus (),
14806 "failed to parse block expr in closure");
14807 add_error (std::move (error));
14808
14809 // skip somewhere?
14810 return nullptr;
14811 }
14812
14813 return std::unique_ptr<AST::ClosureExprInnerTyped> (
14814 new AST::ClosureExprInnerTyped (std::move (type), std::move (block),
14815 std::move (params), locus, has_move,
14816 std::move (outer_attrs)));
14817 }
14818 else
14819 {
14820 // must be expr-only closure
14821
14822 // parse expr, which is required
14823 std::unique_ptr<AST::Expr> expr = parse_expr ();
14824 if (expr == nullptr)
14825 {
14826 Error error (tok->get_locus (),
14827 "failed to parse expression in closure");
14828 add_error (std::move (error));
14829
14830 // skip somewhere?
14831 return nullptr;
14832 }
14833
14834 return std::unique_ptr<AST::ClosureExprInner> (
14835 new AST::ClosureExprInner (std::move (expr), std::move (params), locus,
14836 has_move, std::move (outer_attrs)));
14837 }
14838}
14839
14840/* Parses a tuple index expression (pratt-parsed) from a 'float' token as a
14841 * result of lexer misidentification. */
14842template <typename ManagedTokenSource>
14843std::unique_ptr<AST::TupleIndexExpr>
14844Parser<ManagedTokenSource>::parse_tuple_index_expr_float (
14845 const_TokenPtr tok, std::unique_ptr<AST::Expr> tuple_expr,
14846 AST::AttrVec outer_attrs, ParseRestrictions restrictions ATTRIBUTE_UNUSED)
14847{
14848 // only works on float literals
14849 if (tok->get_id () != FLOAT_LITERAL)
14850 return nullptr;
14851
14852 // DEBUG:
14853 rust_debug ("exact string form of float: '%s'", tok->get_str ().c_str ());
14854
14855 // get float string and remove dot and initial 0
14856 std::string index_str = tok->get_str ();
14857 index_str.erase (index_str.begin ());
14858
14859 // get int from string
14860 int index = atoi (index_str.c_str ());
14861
14862 Location locus = tuple_expr->get_locus ();
14863
14864 return std::unique_ptr<AST::TupleIndexExpr> (
14865 new AST::TupleIndexExpr (std::move (tuple_expr), index,
14866 std::move (outer_attrs), locus));
14867}
14868
14869// Returns true if the next token is END, ELSE, or EOF;
14870template <typename ManagedTokenSource>
14871bool
14872Parser<ManagedTokenSource>::done_end_or_else ()
14873{
14874 const_TokenPtr t = lexer.peek_token ();
14875 return (t->get_id () == RIGHT_CURLY || t->get_id () == ELSE
14876 || t->get_id () == END_OF_FILE);
14877}
14878
14879// Returns true if the next token is END or EOF.
14880template <typename ManagedTokenSource>
14881bool
14882Parser<ManagedTokenSource>::done_end ()
14883{
14884 const_TokenPtr t = lexer.peek_token ();
14885 return (t->get_id () == RIGHT_CURLY || t->get_id () == END_OF_FILE);
14886}
14887
14888// Dumps lexer output to stderr.
14889template <typename ManagedTokenSource>
14890void
14891Parser<ManagedTokenSource>::debug_dump_lex_output (std::ostream &out)
14892{
14893 /* TODO: a better implementation of "lexer dump" (as in dump what was
14894 * actually tokenised) would actually be to "write" a token to a file every
14895 * time skip_token() here was called. This would reflect the parser
14896 * modifications to the token stream, such as fixing the template angle
14897 * brackets. */
14898
14899 const_TokenPtr tok = lexer.peek_token ();
14900
14901 while (true)
14902 {
14903 if (tok->get_id () == Rust::END_OF_FILE)
14904 break;
14905
14906 bool has_text = tok->get_id () == Rust::IDENTIFIER
14907 || tok->get_id () == Rust::INT_LITERAL
14908 || tok->get_id () == Rust::FLOAT_LITERAL
14909 || tok->get_id () == Rust::STRING_LITERAL
14910 || tok->get_id () == Rust::CHAR_LITERAL
14911 || tok->get_id () == Rust::BYTE_STRING_LITERAL
14912 || tok->get_id () == Rust::BYTE_CHAR_LITERAL;
14913
14914 Location loc = tok->get_locus ();
14915
14916 out << "<id=";
14917 out << tok->token_id_to_str ();
14918 out << has_text ? (std::string (", text=") + tok->get_str ()
14919 + std::string (", typehint=")
14920 + std::string (tok->get_type_hint_str ()))
14921 : "";
14922 out << lexer.get_line_map ()->to_string (loc);
14923
14924 lexer.skip_token ();
14925 tok = lexer.peek_token ();
14926 }
14927}
14928
14929// Parses crate and dumps AST to stderr, recursively.
14930template <typename ManagedTokenSource>
14931void
14932Parser<ManagedTokenSource>::debug_dump_ast_output (AST::Crate &crate,
14933 std::ostream &out)
14934{
14935 out << crate.as_string ();
14936}
14937} // namespace Rust