1 // Copyright (C) 2020-2025 Free Software Foundation, Inc.
3 // This file is part of GCC.
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
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
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/>.
19 /* Template implementation for Rust::Parser. Previously in rust-parse.cc (before
20 * Parser was template). Separated from rust-parse.h for readability. */
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. */
25 #include "rust-common.h"
26 #include "rust-expr.h"
27 #include "rust-item.h"
28 #include "rust-common.h"
29 #include "rust-token.h"
30 #define INCLUDE_ALGORITHM
31 #include "rust-diagnostics.h"
32 #include "rust-dir-owner.h"
33 #include "rust-attribute-values.h"
34 #include "rust-keyword-values.h"
35 #include "rust-edition.h"
40 // Left binding powers of operations.
52 LBP_FUNCTION_CALL
= 80,
53 LBP_ARRAY_REF
= LBP_FUNCTION_CALL
,
55 LBP_QUESTION_MARK
= 75, // unary postfix - counts as left
57 LBP_UNARY_PLUS
= 70, // Used only when the null denotation is +
58 LBP_UNARY_MINUS
= LBP_UNARY_PLUS
, // Used only when the null denotation is -
59 LBP_UNARY_ASTERISK
= LBP_UNARY_PLUS
, // deref operator - unary prefix
60 LBP_UNARY_EXCLAM
= LBP_UNARY_PLUS
,
61 LBP_UNARY_AMP
= LBP_UNARY_PLUS
,
62 LBP_UNARY_AMP_MUT
= LBP_UNARY_PLUS
,
74 LBP_R_SHIFT
= LBP_L_SHIFT
,
83 LBP_NOT_EQUAL
= LBP_EQUAL
,
84 LBP_SMALLER_THAN
= LBP_EQUAL
,
85 LBP_SMALLER_EQUAL
= LBP_EQUAL
,
86 LBP_GREATER_THAN
= LBP_EQUAL
,
87 LBP_GREATER_EQUAL
= LBP_EQUAL
,
94 LBP_DOT_DOT_EQ
= LBP_DOT_DOT
,
96 // TODO: note all these assig operators are RIGHT associative!
98 LBP_PLUS_ASSIG
= LBP_ASSIG
,
99 LBP_MINUS_ASSIG
= LBP_ASSIG
,
100 LBP_MULT_ASSIG
= LBP_ASSIG
,
101 LBP_DIV_ASSIG
= LBP_ASSIG
,
102 LBP_MOD_ASSIG
= LBP_ASSIG
,
103 LBP_AMP_ASSIG
= LBP_ASSIG
,
104 LBP_PIPE_ASSIG
= LBP_ASSIG
,
105 LBP_CARET_ASSIG
= LBP_ASSIG
,
106 LBP_L_SHIFT_ASSIG
= LBP_ASSIG
,
107 LBP_R_SHIFT_ASSIG
= LBP_ASSIG
,
109 // return, break, and closures as lowest priority?
111 LBP_BREAK
= LBP_RETURN
,
112 LBP_CLOSURE
= LBP_RETURN
, // unary prefix operators
118 // used for break, continue, return, and yield
120 // used for range (although weird comment in rustc about this)
122 // used for binary operators mentioned below - also cast, colon (type),
124 PREC_BINOP
= FROM_ASSOC_OP
,
125 // used for box, address_of, let, unary (again, weird comment on let)
127 // used for await, call, method call, field, index, try,
128 // inline asm, macro invocation
130 // used for array, repeat, tuple, literal, path, paren, if,
131 // while, for, 'loop', match, block, try block, async, struct
133 PREC_FORCE_PAREN
= 100,
140 /* Returns whether the token can start a type (i.e. there is a valid type
141 * beginning with the token). */
143 can_tok_start_type (TokenId id
)
160 case SCOPE_RESOLUTION
:
177 /* Returns whether the token id is (or is likely to be) a right angle bracket.
178 * i.e. '>', '>>', '>=' and '>>=' tokens. */
180 is_right_angle_tok (TokenId id
)
186 case GREATER_OR_EQUAL
:
194 /* HACK-y special handling for skipping a right angle token at the end of
196 * Currently, this replaces the "current token" with one that is identical
197 * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad
198 * for several reasons - it modifies the token stream to something that
199 * actually doesn't make syntactic sense, it may not worked if the token
200 * has already been skipped, etc. It was done because it would not
201 * actually require inserting new items into the token stream (which I
202 * thought would take more work to not mess up) and because I wasn't sure
203 * if the "already seen right angle" flag in the parser would work
205 * Those two other approaches listed are in my opinion actually better
206 * long-term - insertion is probably best as it reflects syntactically
207 * what occurs. On the other hand, I need to do a code audit to make sure
208 * that insertion doesn't mess anything up. So that's a FIXME. */
209 template <typename ManagedTokenSource
>
211 Parser
<ManagedTokenSource
>::skip_generics_right_angle ()
213 /* OK, new great idea. Have a lexer method called
214 * "split_current_token(TokenType newLeft, TokenType newRight)", which is
215 * called here with whatever arguments are appropriate. That lexer method
216 * handles "replacing" the current token with the "newLeft" and "inserting"
217 * the next token with the "newRight" (and creating a location, etc. for it)
220 /* HACK: special handling for right shift '>>', greater or equal '>=', and
221 * right shift assig */
223 const_TokenPtr tok
= lexer
.peek_token ();
224 switch (tok
->get_id ())
227 // this is good - skip token
231 // new implementation that should be better
232 lexer
.split_current_token (RIGHT_ANGLE
, RIGHT_ANGLE
);
236 case GREATER_OR_EQUAL
: {
237 // new implementation that should be better
238 lexer
.split_current_token (RIGHT_ANGLE
, EQUAL
);
242 case RIGHT_SHIFT_EQ
: {
243 // new implementation that should be better
244 lexer
.split_current_token (RIGHT_ANGLE
, GREATER_OR_EQUAL
);
249 add_error (Error (tok
->get_locus (),
250 "expected %<>%> at end of generic argument - found %qs",
251 tok
->get_token_description ()));
256 /* Gets left binding power for specified token.
257 * Not suitable for use at the moment or possibly ever because binding power
258 * cannot be purely determined from operator token with Rust grammar - e.g.
259 * method call and field access have
260 * different left binding powers but the same operator token. */
261 template <typename ManagedTokenSource
>
263 Parser
<ManagedTokenSource
>::left_binding_power (const_TokenPtr token
)
265 // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
266 switch (token
->get_id ())
268 /* TODO: issue here - distinguish between method calls and field access
269 * somehow? Also would have to distinguish between paths and function
270 * calls (:: operator), maybe more stuff. */
271 /* Current plan for tackling LBP - don't do it based on token, use
272 * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr
273 * and handle other expressions without it. rustc only considers
274 * arithmetic, logical/relational, 'as',
275 * '?=', ranges, colons, and assignment to have operator precedence and
276 * associativity rules applicable. It then has
277 * a separate "ExprPrecedence" that also includes binary operators. */
279 // TODO: handle operator overloading - have a function replace the
285 case SCOPE_RESOLUTION
:
287 "possible error - looked up LBP of scope resolution operator. should "
288 "be handled elsewhere.");
291 /* Resolved by lookahead HACK that should work with current code. If next
292 * token is identifier and token after that isn't parenthesised expression
293 * list, it is a field reference. */
295 if (lexer
.peek_token (1)->get_id () == IDENTIFIER
296 && lexer
.peek_token (2)->get_id () != LEFT_PAREN
)
298 return LBP_FIELD_EXPR
;
300 return LBP_METHOD_CALL
;
303 return LBP_FUNCTION_CALL
;
306 return LBP_ARRAY_REF
;
308 // postfix question mark (i.e. error propagation expression)
310 return LBP_QUESTION_MARK
;
347 return LBP_NOT_EQUAL
;
349 return LBP_GREATER_THAN
;
350 case GREATER_OR_EQUAL
:
351 return LBP_GREATER_EQUAL
;
353 return LBP_SMALLER_THAN
;
355 return LBP_SMALLER_EQUAL
;
358 return LBP_LOGICAL_AND
;
361 return LBP_LOGICAL_OR
;
367 return LBP_DOT_DOT_EQ
;
372 return LBP_PLUS_ASSIG
;
374 return LBP_MINUS_ASSIG
;
376 return LBP_MULT_ASSIG
;
378 return LBP_DIV_ASSIG
;
380 return LBP_MOD_ASSIG
;
382 return LBP_AMP_ASSIG
;
384 return LBP_PIPE_ASSIG
;
386 return LBP_CARET_ASSIG
;
388 return LBP_L_SHIFT_ASSIG
;
390 return LBP_R_SHIFT_ASSIG
;
392 /* HACK: float literal due to lexer misidentifying a dot then an integer as
395 return LBP_FIELD_EXPR
;
396 // field expr is same as tuple expr in precedence, i imagine
397 // TODO: is this needed anymore? lexer shouldn't do that anymore
399 // anything that can't appear in an infix position is given lowest priority
405 // Returns true when current token is EOF.
406 template <typename ManagedTokenSource
>
408 Parser
<ManagedTokenSource
>::done_end_of_file ()
410 return lexer
.peek_token ()->get_id () == END_OF_FILE
;
413 // Parses a sequence of items within a module or the implicit top-level module
415 template <typename ManagedTokenSource
>
416 std::vector
<std::unique_ptr
<AST::Item
>>
417 Parser
<ManagedTokenSource
>::parse_items ()
419 std::vector
<std::unique_ptr
<AST::Item
>> items
;
421 const_TokenPtr t
= lexer
.peek_token ();
422 while (t
->get_id () != END_OF_FILE
)
424 std::unique_ptr
<AST::Item
> item
= parse_item (false);
427 Error
error (lexer
.peek_token ()->get_locus (),
428 "failed to parse item in crate");
429 add_error (std::move (error
));
431 // TODO: should all items be cleared?
432 items
= std::vector
<std::unique_ptr
<AST::Item
>> ();
436 items
.push_back (std::move (item
));
438 t
= lexer
.peek_token ();
444 // Parses a crate (compilation unit) - entry point
445 template <typename ManagedTokenSource
>
446 std::unique_ptr
<AST::Crate
>
447 Parser
<ManagedTokenSource
>::parse_crate ()
449 // parse inner attributes
450 AST::AttrVec inner_attrs
= parse_inner_attributes ();
453 std::vector
<std::unique_ptr
<AST::Item
>> items
= parse_items ();
456 for (const auto &error
: error_table
)
459 return std::unique_ptr
<AST::Crate
> (
460 new AST::Crate (std::move (items
), std::move (inner_attrs
)));
463 // Parse a contiguous block of inner attributes.
464 template <typename ManagedTokenSource
>
466 Parser
<ManagedTokenSource
>::parse_inner_attributes ()
468 AST::AttrVec inner_attributes
;
470 // only try to parse it if it starts with "#!" not only "#"
471 while ((lexer
.peek_token ()->get_id () == HASH
472 && lexer
.peek_token (1)->get_id () == EXCLAM
)
473 || lexer
.peek_token ()->get_id () == INNER_DOC_COMMENT
)
475 AST::Attribute inner_attr
= parse_inner_attribute ();
477 /* Ensure only valid inner attributes are added to the inner_attributes
479 if (!inner_attr
.is_empty ())
481 inner_attributes
.push_back (std::move (inner_attr
));
485 /* If no more valid inner attributes, break out of loop (only
486 * contiguous inner attributes parsed). */
491 inner_attributes
.shrink_to_fit ();
492 return inner_attributes
;
495 // Parse a inner or outer doc comment into an doc attribute
496 template <typename ManagedTokenSource
>
497 std::tuple
<AST::SimplePath
, std::unique_ptr
<AST::AttrInput
>, location_t
>
498 Parser
<ManagedTokenSource
>::parse_doc_comment ()
500 const_TokenPtr token
= lexer
.peek_token ();
501 location_t locus
= token
->get_locus ();
502 AST::SimplePathSegment
segment (Values::Attributes::DOC
, locus
);
503 std::vector
<AST::SimplePathSegment
> segments
;
504 segments
.push_back (std::move (segment
));
505 AST::SimplePath
attr_path (std::move (segments
), false, locus
);
506 AST::LiteralExpr
lit_expr (token
->get_str (), AST::Literal::STRING
,
507 PrimitiveCoreType::CORETYPE_STR
, {}, locus
);
508 std::unique_ptr
<AST::AttrInput
> attr_input (
509 new AST::AttrInputLiteral (std::move (lit_expr
)));
511 return std::make_tuple (std::move (attr_path
), std::move (attr_input
), locus
);
514 // Parse a single inner attribute.
515 template <typename ManagedTokenSource
>
517 Parser
<ManagedTokenSource
>::parse_inner_attribute ()
519 if (lexer
.peek_token ()->get_id () == INNER_DOC_COMMENT
)
521 auto values
= parse_doc_comment ();
522 auto path
= std::move (std::get
<0> (values
));
523 auto input
= std::move (std::get
<1> (values
));
524 auto loc
= std::get
<2> (values
);
525 return AST::Attribute (std::move (path
), std::move (input
), loc
, true);
528 if (lexer
.peek_token ()->get_id () != HASH
)
530 Error
error (lexer
.peek_token ()->get_locus (),
531 "BUG: token %<#%> is missing, but %<parse_inner_attribute%> "
533 add_error (std::move (error
));
535 return AST::Attribute::create_empty ();
539 if (lexer
.peek_token ()->get_id () != EXCLAM
)
541 Error
error (lexer
.peek_token ()->get_locus (),
542 "expected %<!%> or %<[%> for inner attribute");
543 add_error (std::move (error
));
545 return AST::Attribute::create_empty ();
549 if (!skip_token (LEFT_SQUARE
))
550 return AST::Attribute::create_empty ();
552 auto values
= parse_attribute_body ();
554 auto path
= std::move (std::get
<0> (values
));
555 auto input
= std::move (std::get
<1> (values
));
556 auto loc
= std::get
<2> (values
);
557 auto actual_attribute
558 = AST::Attribute (std::move (path
), std::move (input
), loc
, true);
560 if (!skip_token (RIGHT_SQUARE
))
561 return AST::Attribute::create_empty ();
563 return actual_attribute
;
566 // Parses the body of an attribute (inner or outer).
567 template <typename ManagedTokenSource
>
568 std::tuple
<AST::SimplePath
, std::unique_ptr
<AST::AttrInput
>, location_t
>
569 Parser
<ManagedTokenSource
>::parse_attribute_body ()
571 location_t locus
= lexer
.peek_token ()->get_locus ();
573 AST::SimplePath attr_path
= parse_simple_path ();
574 // ensure path is valid to parse attribute input
575 if (attr_path
.is_empty ())
577 Error
error (lexer
.peek_token ()->get_locus (),
578 "empty simple path in attribute");
579 add_error (std::move (error
));
581 // Skip past potential further info in attribute (i.e. attr_input)
582 skip_after_end_attribute ();
583 return std::make_tuple (std::move (attr_path
), nullptr, UNDEF_LOCATION
);
586 std::unique_ptr
<AST::AttrInput
> attr_input
= parse_attr_input ();
587 // AttrInput is allowed to be null, so no checks here
589 return std::make_tuple (std::move (attr_path
), std::move (attr_input
), locus
);
592 /* Determines whether token is a valid simple path segment. This does not
593 * include scope resolution operators. */
595 is_simple_path_segment (TokenId id
)
605 // assume that dollar sign leads to $crate
612 // Parses a SimplePath AST node, if it exists. Does nothing otherwise.
613 template <typename ManagedTokenSource
>
615 Parser
<ManagedTokenSource
>::parse_simple_path ()
617 bool has_opening_scope_resolution
= false;
618 location_t locus
= UNKNOWN_LOCATION
;
620 // don't parse anything if not a path upfront
621 if (!is_simple_path_segment (lexer
.peek_token ()->get_id ())
622 && !is_simple_path_segment (lexer
.peek_token (1)->get_id ()))
623 return AST::SimplePath::create_empty ();
625 /* Checks for opening scope resolution (i.e. global scope fully-qualified
627 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
)
629 has_opening_scope_resolution
= true;
631 locus
= lexer
.peek_token ()->get_locus ();
636 // Parse single required simple path segment
637 AST::SimplePathSegment segment
= parse_simple_path_segment ();
639 // get location if not gotten already
640 if (locus
== UNKNOWN_LOCATION
)
641 locus
= segment
.get_locus ();
643 std::vector
<AST::SimplePathSegment
> segments
;
645 // Return empty vector if first, actually required segment is an error
646 if (segment
.is_error ())
647 return AST::SimplePath::create_empty ();
649 segments
.push_back (std::move (segment
));
651 // Parse all other simple path segments
652 while (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
)
654 // Skip scope resolution operator
657 AST::SimplePathSegment new_segment
= parse_simple_path_segment ();
659 // Return path as currently constructed if segment in error state.
660 if (new_segment
.is_error ())
663 segments
.push_back (std::move (new_segment
));
666 // DEBUG: check for any empty segments
667 for (const auto &seg
: segments
)
672 "when parsing simple path, somehow empty path segment was "
673 "not filtered out. Path begins with '%s'",
674 segments
.at (0).as_string ().c_str ());
678 return AST::SimplePath (std::move (segments
), has_opening_scope_resolution
,
680 /* TODO: now that is_simple_path_segment exists, could probably start
681 * actually making errors upon parse failure of segments and whatever */
684 /* Parses a single SimplePathSegment (does not handle the scope resolution
686 template <typename ManagedTokenSource
>
687 AST::SimplePathSegment
688 Parser
<ManagedTokenSource
>::parse_simple_path_segment ()
690 using namespace Values
;
691 const_TokenPtr t
= lexer
.peek_token ();
692 switch (t
->get_id ())
697 return AST::SimplePathSegment (t
->get_str (), t
->get_locus ());
701 return AST::SimplePathSegment (Keywords::SUPER
, t
->get_locus ());
705 return AST::SimplePathSegment (Keywords::SELF
, t
->get_locus ());
709 return AST::SimplePathSegment (Keywords::CRATE
, t
->get_locus ());
711 if (lexer
.peek_token (1)->get_id () == CRATE
)
713 lexer
.skip_token (1);
715 return AST::SimplePathSegment ("$crate", t
->get_locus ());
719 // do nothing but inactivates warning from gcc when compiling
720 /* could put the rust_error_at thing here but fallthrough (from failing
721 * $crate condition) isn't completely obvious if it is. */
723 // test prevent error
724 return AST::SimplePathSegment::create_error ();
728 t->get_locus(), "invalid token '%s' in simple path segment",
729 t->get_token_description());*/
730 // this is not necessarily an error, e.g. end of path
731 // return AST::SimplePathSegment::create_error();
734 // Parses a PathIdentSegment - an identifier segment of a non-SimplePath path.
735 template <typename ManagedTokenSource
>
736 AST::PathIdentSegment
737 Parser
<ManagedTokenSource
>::parse_path_ident_segment ()
739 const_TokenPtr t
= lexer
.peek_token ();
740 switch (t
->get_id ())
745 return AST::PathIdentSegment (t
->get_str (), t
->get_locus ());
749 return AST::PathIdentSegment (Values::Keywords::SUPER
, t
->get_locus ());
753 return AST::PathIdentSegment (Values::Keywords::SELF
, t
->get_locus ());
757 return AST::PathIdentSegment (Values::Keywords::SELF_ALIAS
,
762 return AST::PathIdentSegment (Values::Keywords::CRATE
, t
->get_locus ());
764 if (lexer
.peek_token (1)->get_id () == CRATE
)
766 lexer
.skip_token (1);
768 return AST::PathIdentSegment ("$crate", t
->get_locus ());
772 /* do nothing but inactivates warning from gcc when compiling
773 * could put the error_at thing here but fallthrough (from failing $crate
774 * condition) isn't completely obvious if it is. */
776 // test prevent error
777 return AST::PathIdentSegment::create_error ();
780 // not necessarily an error
783 // Parses an AttrInput AST node (polymorphic, as AttrInput is abstract)
784 template <typename ManagedTokenSource
>
785 std::unique_ptr
<AST::AttrInput
>
786 Parser
<ManagedTokenSource
>::parse_attr_input ()
788 const_TokenPtr t
= lexer
.peek_token ();
789 switch (t
->get_id ())
794 // must be a delimited token tree, so parse that
795 std::unique_ptr
<AST::AttrInput
> input_tree (
796 new AST::DelimTokenTree (parse_delim_token_tree ()));
798 // TODO: potential checks on DelimTokenTree before returning
806 t
= lexer
.peek_token ();
808 // attempt to parse macro
809 // TODO: macros may/may not be allowed in attributes
810 // this is needed for "#[doc = include_str!(...)]"
811 if (is_simple_path_segment (t
->get_id ()))
813 std::unique_ptr
<AST::MacroInvocation
> invoke
814 = parse_macro_invocation ({});
819 return std::unique_ptr
<AST::AttrInput
> (
820 new AST::AttrInputMacro (std::move (invoke
)));
823 /* Ensure token is a "literal expression" (literally only a literal
824 * token of any type) */
825 if (!t
->is_literal ())
829 "unknown token %qs in attribute body - literal expected",
830 t
->get_token_description ());
831 add_error (std::move (error
));
833 skip_after_end_attribute ();
837 AST::Literal::LitType lit_type
= AST::Literal::STRING
;
838 // Crappy mapping of token type to literal type
839 switch (t
->get_id ())
842 lit_type
= AST::Literal::INT
;
845 lit_type
= AST::Literal::FLOAT
;
848 lit_type
= AST::Literal::CHAR
;
850 case BYTE_CHAR_LITERAL
:
851 lit_type
= AST::Literal::BYTE
;
853 case BYTE_STRING_LITERAL
:
854 lit_type
= AST::Literal::BYTE_STRING
;
856 case RAW_STRING_LITERAL
:
857 lit_type
= AST::Literal::RAW_STRING
;
861 lit_type
= AST::Literal::STRING
;
862 break; // TODO: raw string? don't eliminate it from lexer?
865 // create actual LiteralExpr
866 AST::LiteralExpr
lit_expr (t
->get_str (), lit_type
, t
->get_type_hint (),
867 {}, t
->get_locus ());
870 std::unique_ptr
<AST::AttrInput
> attr_input_lit (
871 new AST::AttrInputLiteral (std::move (lit_expr
)));
873 // do checks or whatever? none required, really
875 // FIXME: shouldn't a skip token be required here?
877 return attr_input_lit
;
881 // means AttrInput is missing, which is allowed
885 Error (t
->get_locus (),
886 "unknown token %qs in attribute body - attribute input or "
888 t
->get_token_description ()));
890 skip_after_end_attribute ();
894 // TODO: find out how to stop gcc error on "no return value"
897 /* Returns true if the token id matches the delimiter type. Note that this only
898 * operates for END delimiter tokens. */
900 token_id_matches_delims (TokenId token_id
, AST::DelimType delim_type
)
902 return ((token_id
== RIGHT_PAREN
&& delim_type
== AST::PARENS
)
903 || (token_id
== RIGHT_SQUARE
&& delim_type
== AST::SQUARE
)
904 || (token_id
== RIGHT_CURLY
&& delim_type
== AST::CURLY
));
907 /* Returns true if the likely result of parsing the next few tokens is a path.
908 * Not guaranteed, though, especially in the case of syntax errors. */
910 is_likely_path_next (TokenId next_token_id
)
912 switch (next_token_id
)
919 // maybe - maybe do extra check. But then requires another TokenId.
921 case SCOPE_RESOLUTION
:
928 // Parses a delimited token tree
929 template <typename ManagedTokenSource
>
931 Parser
<ManagedTokenSource
>::parse_delim_token_tree ()
933 const_TokenPtr t
= lexer
.peek_token ();
935 location_t initial_loc
= t
->get_locus ();
937 // save delim type to ensure it is reused later
938 AST::DelimType delim_type
= AST::PARENS
;
940 // Map tokens to DelimType
941 switch (t
->get_id ())
944 delim_type
= AST::PARENS
;
947 delim_type
= AST::SQUARE
;
950 delim_type
= AST::CURLY
;
953 add_error (Error (t
->get_locus (),
954 "unexpected token %qs - expecting delimiters (for a "
955 "delimited token tree)",
956 t
->get_token_description ()));
958 return AST::DelimTokenTree::create_empty ();
961 // parse actual token tree vector - 0 or more
962 std::vector
<std::unique_ptr
<AST::TokenTree
>> token_trees_in_tree
;
964 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
965 token_trees_in_tree
.push_back (std::move (delim_open
));
967 // repeat loop until finding the matching delimiter
968 t
= lexer
.peek_token ();
969 while (!token_id_matches_delims (t
->get_id (), delim_type
)
970 && t
->get_id () != END_OF_FILE
)
972 std::unique_ptr
<AST::TokenTree
> tok_tree
= parse_token_tree ();
974 if (tok_tree
== nullptr)
976 // TODO: is this error handling appropriate?
979 "failed to parse token tree in delimited token tree - found %qs",
980 t
->get_token_description ());
981 add_error (std::move (error
));
983 return AST::DelimTokenTree::create_empty ();
986 token_trees_in_tree
.push_back (std::move (tok_tree
));
988 // lexer.skip_token();
989 t
= lexer
.peek_token ();
992 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
993 token_trees_in_tree
.push_back (std::move (delim_close
));
995 AST::DelimTokenTree
token_tree (delim_type
, std::move (token_trees_in_tree
),
998 // parse end delimiters
999 t
= lexer
.peek_token ();
1001 if (token_id_matches_delims (t
->get_id (), delim_type
))
1003 // tokens match opening delimiter, so skip.
1004 lexer
.skip_token ();
1007 rust_debug ("finished parsing new delim token tree - peeked token is now "
1008 "'%s' while t is '%s'",
1009 lexer
.peek_token ()->get_token_description (),
1010 t
->get_token_description ());
1016 // tokens don't match opening delimiters, so produce error
1017 Error
error (t
->get_locus (),
1018 "unexpected token %qs - expecting closing delimiter %qs "
1019 "(for a delimited token tree)",
1020 t
->get_token_description (),
1021 (delim_type
== AST::PARENS
1023 : (delim_type
== AST::SQUARE
? "]" : "}")));
1024 add_error (std::move (error
));
1026 /* return empty token tree despite possibly parsing valid token tree -
1027 * TODO is this a good idea? */
1028 return AST::DelimTokenTree::create_empty ();
1032 // Parses an identifier/keyword as a Token
1033 template <typename ManagedTokenSource
>
1034 std::unique_ptr
<AST::Token
>
1035 Parser
<ManagedTokenSource
>::parse_identifier_or_keyword_token ()
1037 const_TokenPtr t
= lexer
.peek_token ();
1039 if (t
->get_id () == IDENTIFIER
|| token_id_is_keyword (t
->get_id ()))
1041 lexer
.skip_token ();
1042 return std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
1050 /* Parses a TokenTree syntactical production. This is either a delimited token
1051 * tree or a non-delimiter token. */
1052 template <typename ManagedTokenSource
>
1053 std::unique_ptr
<AST::TokenTree
>
1054 Parser
<ManagedTokenSource
>::parse_token_tree ()
1056 const_TokenPtr t
= lexer
.peek_token ();
1058 switch (t
->get_id ())
1063 // Parse delimited token tree
1064 // TODO: use move rather than copy constructor
1065 return std::unique_ptr
<AST::DelimTokenTree
> (
1066 new AST::DelimTokenTree (parse_delim_token_tree ()));
1070 // error - should not be called when this a token
1072 Error (t
->get_locus (),
1073 "unexpected closing delimiter %qs - token tree requires "
1074 "either paired delimiters or non-delimiter tokens",
1075 t
->get_token_description ()));
1077 lexer
.skip_token ();
1080 // parse token itself as TokenTree
1081 lexer
.skip_token ();
1082 return std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
1086 template <typename ManagedTokenSource
>
1088 Parser
<ManagedTokenSource
>::is_macro_rules_def (const_TokenPtr t
)
1090 auto macro_name
= lexer
.peek_token (2)->get_id ();
1092 bool allowed_macro_name
= (macro_name
== IDENTIFIER
|| macro_name
== TRY
);
1094 return t
->get_str () == Values::WeakKeywords::MACRO_RULES
1095 && lexer
.peek_token (1)->get_id () == EXCLAM
&& allowed_macro_name
;
1098 // Parses a single item
1099 template <typename ManagedTokenSource
>
1100 std::unique_ptr
<AST::Item
>
1101 Parser
<ManagedTokenSource
>::parse_item (bool called_from_statement
)
1103 // has a "called_from_statement" parameter for better error message handling
1105 // parse outer attributes for item
1106 AST::AttrVec outer_attrs
= parse_outer_attributes ();
1107 const_TokenPtr t
= lexer
.peek_token ();
1109 switch (t
->get_id ())
1112 // not necessarily an error, unless we just read outer
1113 // attributes which needs to be attached
1114 if (!outer_attrs
.empty ())
1116 Rust::AST::Attribute attr
= outer_attrs
.back ();
1117 Error
error (attr
.get_locus (),
1118 "expected item after outer attribute or doc comment");
1119 add_error (std::move (error
));
1138 /* TODO: implement union keyword but not really because of
1139 * context-dependence crappy hack way to parse a union written below to
1140 * separate it from the good code. */
1142 case UNSAFE
: // maybe - unsafe traits are a thing
1143 // if any of these (should be all possible VisItem prefixes), parse a
1145 return parse_vis_item (std::move (outer_attrs
));
1151 // almost certainly macro invocation semi
1152 return parse_macro_invocation_semi (std::move (outer_attrs
));
1154 // crappy hack to do union "keyword"
1156 // TODO: ensure std::string and literal comparison works
1157 if (t
->get_str () == Values::WeakKeywords::UNION
1158 && lexer
.peek_token (1)->get_id () == IDENTIFIER
)
1160 return parse_vis_item (std::move (outer_attrs
));
1161 // or should this go straight to parsing union?
1163 else if (t
->get_str () == Values::WeakKeywords::DEFAULT
1164 && lexer
.peek_token (1)->get_id () != EXCLAM
)
1166 add_error (Error (t
->get_locus (),
1167 "%qs is only allowed on items within %qs blocks",
1168 "default", "impl"));
1171 else if (is_macro_rules_def (t
))
1173 // macro_rules! macro item
1174 return parse_macro_rules_def (std::move (outer_attrs
));
1176 else if (lexer
.peek_token (1)->get_id () == SCOPE_RESOLUTION
1177 || lexer
.peek_token (1)->get_id () == EXCLAM
)
1179 /* path (probably) or macro invocation, so probably a macro invocation
1181 return parse_macro_invocation_semi (std::move (outer_attrs
));
1185 // otherwise unrecognised
1186 add_error (Error (t
->get_locus (),
1187 "unrecognised token %qs for start of %s",
1188 t
->get_token_description (),
1189 called_from_statement
? "statement" : "item"));
1197 // Parses a contiguous block of outer attributes.
1198 template <typename ManagedTokenSource
>
1200 Parser
<ManagedTokenSource
>::parse_outer_attributes ()
1202 AST::AttrVec outer_attributes
;
1204 while (lexer
.peek_token ()->get_id ()
1205 == HASH
/* Can also be #!, which catches errors. */
1206 || lexer
.peek_token ()->get_id () == OUTER_DOC_COMMENT
1207 || lexer
.peek_token ()->get_id ()
1208 == INNER_DOC_COMMENT
) /* For error handling. */
1210 AST::Attribute outer_attr
= parse_outer_attribute ();
1212 /* Ensure only valid outer attributes are added to the outer_attributes
1214 if (!outer_attr
.is_empty ())
1216 outer_attributes
.push_back (std::move (outer_attr
));
1220 /* If no more valid outer attributes, break out of loop (only
1221 * contiguous outer attributes parsed). */
1226 outer_attributes
.shrink_to_fit ();
1227 return outer_attributes
;
1229 /* TODO: this shares basically all code with parse_inner_attributes except
1230 * function call - find way of making it more modular? function pointer? */
1233 // Parse a single outer attribute.
1234 template <typename ManagedTokenSource
>
1236 Parser
<ManagedTokenSource
>::parse_outer_attribute ()
1238 if (lexer
.peek_token ()->get_id () == OUTER_DOC_COMMENT
)
1240 auto values
= parse_doc_comment ();
1241 auto path
= std::move (std::get
<0> (values
));
1242 auto input
= std::move (std::get
<1> (values
));
1243 auto loc
= std::get
<2> (values
);
1244 return AST::Attribute (std::move (path
), std::move (input
), loc
, false);
1247 if (lexer
.peek_token ()->get_id () == INNER_DOC_COMMENT
)
1250 lexer
.peek_token ()->get_locus (), ErrorCode::E0753
,
1251 "expected outer doc comment, inner doc (%<//!%> or %</*!%>) only "
1252 "allowed at start of item "
1253 "and before any outer attribute or doc (%<#[%>, %<///%> or %</**%>)");
1254 add_error (std::move (error
));
1255 lexer
.skip_token ();
1256 return AST::Attribute::create_empty ();
1259 /* OuterAttribute -> '#' '[' Attr ']' */
1261 if (lexer
.peek_token ()->get_id () != HASH
)
1262 return AST::Attribute::create_empty ();
1264 lexer
.skip_token ();
1266 TokenId id
= lexer
.peek_token ()->get_id ();
1267 if (id
!= LEFT_SQUARE
)
1271 // this is inner attribute syntax, so throw error
1272 // inner attributes were either already parsed or not allowed here.
1274 lexer
.peek_token ()->get_locus (),
1275 "token %<!%> found, indicating inner attribute definition. Inner "
1276 "attributes are not possible at this location");
1277 add_error (std::move (error
));
1279 return AST::Attribute::create_empty ();
1282 lexer
.skip_token ();
1284 auto values
= parse_attribute_body ();
1285 auto path
= std::move (std::get
<0> (values
));
1286 auto input
= std::move (std::get
<1> (values
));
1287 auto loc
= std::get
<2> (values
);
1288 auto actual_attribute
1289 = AST::Attribute (std::move (path
), std::move (input
), loc
, false);
1291 if (lexer
.peek_token ()->get_id () != RIGHT_SQUARE
)
1292 return AST::Attribute::create_empty ();
1294 lexer
.skip_token ();
1296 return actual_attribute
;
1299 // Parses a VisItem (item that can have non-default visibility).
1300 template <typename ManagedTokenSource
>
1301 std::unique_ptr
<AST::VisItem
>
1302 Parser
<ManagedTokenSource
>::parse_vis_item (AST::AttrVec outer_attrs
)
1304 // parse visibility, which may or may not exist
1305 AST::Visibility vis
= parse_visibility ();
1307 // select VisItem to create depending on keyword
1308 const_TokenPtr t
= lexer
.peek_token ();
1310 switch (t
->get_id ())
1313 return parse_module (std::move (vis
), std::move (outer_attrs
));
1315 // lookahead to resolve syntactical production
1316 t
= lexer
.peek_token (1);
1318 switch (t
->get_id ())
1321 return parse_extern_crate (std::move (vis
), std::move (outer_attrs
));
1322 case FN_KW
: // extern function
1323 return parse_function (std::move (vis
), std::move (outer_attrs
));
1324 case LEFT_CURLY
: // extern block
1325 return parse_extern_block (std::move (vis
), std::move (outer_attrs
));
1326 case STRING_LITERAL
: // for specifying extern ABI
1327 // could be extern block or extern function, so more lookahead
1328 t
= lexer
.peek_token (2);
1330 switch (t
->get_id ())
1333 return parse_function (std::move (vis
), std::move (outer_attrs
));
1335 return parse_extern_block (std::move (vis
),
1336 std::move (outer_attrs
));
1339 Error (t
->get_locus (),
1340 "unexpected token %qs in some sort of extern production",
1341 t
->get_token_description ()));
1343 lexer
.skip_token (2); // TODO: is this right thing to do?
1348 Error (t
->get_locus (),
1349 "unexpected token %qs in some sort of extern production",
1350 t
->get_token_description ()));
1352 lexer
.skip_token (1); // TODO: is this right thing to do?
1356 return parse_use_decl (std::move (vis
), std::move (outer_attrs
));
1358 return parse_function (std::move (vis
), std::move (outer_attrs
));
1360 return parse_type_alias (std::move (vis
), std::move (outer_attrs
));
1362 return parse_struct (std::move (vis
), std::move (outer_attrs
));
1364 return parse_enum (std::move (vis
), std::move (outer_attrs
));
1365 // TODO: implement union keyword but not really because of
1366 // context-dependence case UNION: crappy hack to do union "keyword"
1368 if (t
->get_str () == Values::WeakKeywords::UNION
1369 && lexer
.peek_token (1)->get_id () == IDENTIFIER
)
1371 return parse_union (std::move (vis
), std::move (outer_attrs
));
1372 // or should item switch go straight to parsing union?
1379 // lookahead to resolve syntactical production
1380 t
= lexer
.peek_token (1);
1382 switch (t
->get_id ())
1386 return parse_const_item (std::move (vis
), std::move (outer_attrs
));
1388 return parse_async_item (std::move (vis
), std::move (outer_attrs
));
1392 return parse_function (std::move (vis
), std::move (outer_attrs
));
1395 Error (t
->get_locus (),
1396 "unexpected token %qs in some sort of const production",
1397 t
->get_token_description ()));
1399 lexer
.skip_token (1); // TODO: is this right thing to do?
1402 // for async functions
1404 return parse_async_item (std::move (vis
), std::move (outer_attrs
));
1407 return parse_static_item (std::move (vis
), std::move (outer_attrs
));
1410 return parse_trait (std::move (vis
), std::move (outer_attrs
));
1412 return parse_impl (std::move (vis
), std::move (outer_attrs
));
1413 case UNSAFE
: // unsafe traits, unsafe functions, unsafe impls (trait impls),
1414 // lookahead to resolve syntactical production
1415 t
= lexer
.peek_token (1);
1417 switch (t
->get_id ())
1421 return parse_trait (std::move (vis
), std::move (outer_attrs
));
1424 return parse_function (std::move (vis
), std::move (outer_attrs
));
1426 return parse_impl (std::move (vis
), std::move (outer_attrs
));
1428 return parse_module (std::move (vis
), std::move (outer_attrs
));
1431 Error (t
->get_locus (),
1432 "unexpected token %qs in some sort of unsafe production",
1433 t
->get_token_description ()));
1435 lexer
.skip_token (1); // TODO: is this right thing to do?
1439 return parse_decl_macro_def (std::move (vis
), std::move (outer_attrs
));
1441 // otherwise vis item clearly doesn't exist, which is not an error
1442 // has a catch-all post-switch return to allow other breaks to occur
1448 template <typename ManagedTokenSource
>
1449 std::unique_ptr
<AST::Function
>
1450 Parser
<ManagedTokenSource
>::parse_async_item (AST::Visibility vis
,
1451 AST::AttrVec outer_attrs
)
1453 auto offset
= (lexer
.peek_token ()->get_id () == CONST
) ? 1 : 0;
1454 const_TokenPtr t
= lexer
.peek_token (offset
);
1456 if (get_rust_edition () == Edition::E2015
)
1458 add_error (Error (t
->get_locus (), ErrorCode::E0670
,
1459 "%<async fn%> is not permitted in Rust 2015"));
1461 Error::Hint (t
->get_locus (),
1462 "to use %<async fn%>, switch to Rust 2018 or later"));
1465 t
= lexer
.peek_token (offset
+ 1);
1467 switch (t
->get_id ())
1471 return parse_function (std::move (vis
), std::move (outer_attrs
));
1475 Error (t
->get_locus (), "expected item, found keyword %<async%>"));
1477 lexer
.skip_token (1);
1482 // Parses a macro rules definition syntax extension whatever thing.
1483 template <typename ManagedTokenSource
>
1484 std::unique_ptr
<AST::MacroRulesDefinition
>
1485 Parser
<ManagedTokenSource
>::parse_macro_rules_def (AST::AttrVec outer_attrs
)
1487 // ensure that first token is identifier saying "macro_rules"
1488 const_TokenPtr t
= lexer
.peek_token ();
1489 if (t
->get_id () != IDENTIFIER
1490 || t
->get_str () != Values::WeakKeywords::MACRO_RULES
)
1494 "macro rules definition does not start with %<macro_rules%>");
1495 add_error (std::move (error
));
1497 // skip after somewhere?
1500 lexer
.skip_token ();
1501 location_t macro_locus
= t
->get_locus ();
1503 if (!skip_token (EXCLAM
))
1505 // skip after somewhere?
1510 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
1511 if (ident_tok
== nullptr)
1515 Identifier rule_name
{ident_tok
};
1518 rust_debug ("in macro rules def, about to parse parens.");
1520 // save delim type to ensure it is reused later
1521 AST::DelimType delim_type
= AST::PARENS
;
1523 // Map tokens to DelimType
1524 t
= lexer
.peek_token ();
1525 switch (t
->get_id ())
1528 delim_type
= AST::PARENS
;
1531 delim_type
= AST::SQUARE
;
1534 delim_type
= AST::CURLY
;
1537 add_error (Error (t
->get_locus (),
1538 "unexpected token %qs - expecting delimiters (for a "
1539 "macro rules definition)",
1540 t
->get_token_description ()));
1544 lexer
.skip_token ();
1546 // parse actual macro rules
1547 std::vector
<AST::MacroRule
> macro_rules
;
1549 // must be at least one macro rule, so parse it
1550 AST::MacroRule initial_rule
= parse_macro_rule ();
1551 if (initial_rule
.is_error ())
1553 Error
error (lexer
.peek_token ()->get_locus (),
1554 "required first macro rule in macro rules definition "
1555 "could not be parsed");
1556 add_error (std::move (error
));
1558 // skip after somewhere?
1561 macro_rules
.push_back (std::move (initial_rule
));
1564 rust_debug ("successfully pushed back initial macro rule");
1566 t
= lexer
.peek_token ();
1567 // parse macro rules
1568 while (t
->get_id () == SEMICOLON
)
1571 lexer
.skip_token ();
1573 // don't parse if end of macro rules
1574 if (token_id_matches_delims (lexer
.peek_token ()->get_id (), delim_type
))
1578 "broke out of parsing macro rules loop due to finding delim");
1583 // try to parse next rule
1584 AST::MacroRule rule
= parse_macro_rule ();
1585 if (rule
.is_error ())
1587 Error
error (lexer
.peek_token ()->get_locus (),
1588 "failed to parse macro rule in macro rules definition");
1589 add_error (std::move (error
));
1594 macro_rules
.push_back (std::move (rule
));
1597 rust_debug ("successfully pushed back another macro rule");
1599 t
= lexer
.peek_token ();
1602 // parse end delimiters
1603 t
= lexer
.peek_token ();
1604 if (token_id_matches_delims (t
->get_id (), delim_type
))
1606 // tokens match opening delimiter, so skip.
1607 lexer
.skip_token ();
1609 if (delim_type
!= AST::CURLY
)
1611 // skip semicolon at end of non-curly macro definitions
1612 if (!skip_token (SEMICOLON
))
1614 // as this is the end, allow recovery (probably) - may change
1615 return std::unique_ptr
<AST::MacroRulesDefinition
> (
1616 AST::MacroRulesDefinition::mbe (
1617 std::move (rule_name
), delim_type
, std::move (macro_rules
),
1618 std::move (outer_attrs
), macro_locus
));
1622 return std::unique_ptr
<AST::MacroRulesDefinition
> (
1623 AST::MacroRulesDefinition::mbe (std::move (rule_name
), delim_type
,
1624 std::move (macro_rules
),
1625 std::move (outer_attrs
), macro_locus
));
1629 // tokens don't match opening delimiters, so produce error
1630 Error
error (t
->get_locus (),
1631 "unexpected token %qs - expecting closing delimiter %qs "
1632 "(for a macro rules definition)",
1633 t
->get_token_description (),
1634 (delim_type
== AST::PARENS
1636 : (delim_type
== AST::SQUARE
? "]" : "}")));
1637 add_error (std::move (error
));
1639 /* return empty macro definiton despite possibly parsing mostly valid one
1640 * - TODO is this a good idea? */
1645 // Parses a declarative macro 2.0 definition.
1646 template <typename ManagedTokenSource
>
1647 std::unique_ptr
<AST::MacroRulesDefinition
>
1648 Parser
<ManagedTokenSource
>::parse_decl_macro_def (AST::Visibility vis
,
1649 AST::AttrVec outer_attrs
)
1651 // ensure that first token is identifier saying "macro"
1652 const_TokenPtr t
= lexer
.peek_token ();
1653 if (t
->get_id () != MACRO
)
1657 "declarative macro definition does not start with %<macro%>");
1658 add_error (std::move (error
));
1660 // skip after somewhere?
1663 lexer
.skip_token ();
1664 location_t macro_locus
= t
->get_locus ();
1667 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
1668 if (ident_tok
== nullptr)
1672 Identifier rule_name
{ident_tok
};
1674 t
= lexer
.peek_token ();
1675 if (t
->get_id () == LEFT_PAREN
)
1677 // single definiton of macro rule
1678 // e.g. `macro foo($e:expr) {}`
1680 // parse macro matcher
1681 location_t locus
= lexer
.peek_token ()->get_locus ();
1682 AST::MacroMatcher matcher
= parse_macro_matcher ();
1683 if (matcher
.is_error ())
1686 // check delimiter of macro matcher
1687 if (matcher
.get_delim_type () != AST::DelimType::PARENS
)
1689 Error
error (locus
, "only parenthesis can be used for a macro "
1690 "matcher in declarative macro definition");
1691 add_error (std::move (error
));
1695 location_t transcriber_loc
= lexer
.peek_token ()->get_locus ();
1696 AST::DelimTokenTree delim_tok_tree
= parse_delim_token_tree ();
1697 AST::MacroTranscriber
transcriber (delim_tok_tree
, transcriber_loc
);
1699 if (transcriber
.get_token_tree ().get_delim_type ()
1700 != AST::DelimType::CURLY
)
1702 Error
error (transcriber_loc
,
1703 "only braces can be used for a macro transcriber "
1704 "in declarative macro definition");
1705 add_error (std::move (error
));
1709 AST::MacroRule macro_rule
1710 = AST::MacroRule (std::move (matcher
), std::move (transcriber
), locus
);
1711 std::vector
<AST::MacroRule
> macro_rules
;
1712 macro_rules
.push_back (macro_rule
);
1714 return std::unique_ptr
<AST::MacroRulesDefinition
> (
1715 AST::MacroRulesDefinition::decl_macro (std::move (rule_name
),
1717 std::move (outer_attrs
),
1720 else if (t
->get_id () == LEFT_CURLY
)
1722 // multiple definitions of macro rule separated by comma
1723 // e.g. `macro foo { () => {}, ($e:expr) => {}, }`
1726 const_TokenPtr left_curly
= expect_token (LEFT_CURLY
);
1727 if (left_curly
== nullptr)
1732 // parse actual macro rules
1733 std::vector
<AST::MacroRule
> macro_rules
;
1735 // must be at least one macro rule, so parse it
1736 AST::MacroRule initial_rule
= parse_macro_rule ();
1737 if (initial_rule
.is_error ())
1740 lexer
.peek_token ()->get_locus (),
1741 "required first macro rule in declarative macro definition "
1742 "could not be parsed");
1743 add_error (std::move (error
));
1745 // skip after somewhere?
1748 macro_rules
.push_back (std::move (initial_rule
));
1750 t
= lexer
.peek_token ();
1751 // parse macro rules
1752 while (t
->get_id () == COMMA
)
1755 lexer
.skip_token ();
1757 // don't parse if end of macro rules
1758 if (token_id_matches_delims (lexer
.peek_token ()->get_id (),
1764 // try to parse next rule
1765 AST::MacroRule rule
= parse_macro_rule ();
1766 if (rule
.is_error ())
1769 lexer
.peek_token ()->get_locus (),
1770 "failed to parse macro rule in declarative macro definition");
1771 add_error (std::move (error
));
1776 macro_rules
.push_back (std::move (rule
));
1778 t
= lexer
.peek_token ();
1781 // parse right curly
1782 const_TokenPtr right_curly
= expect_token (RIGHT_CURLY
);
1783 if (right_curly
== nullptr)
1788 return std::unique_ptr
<AST::MacroRulesDefinition
> (
1789 AST::MacroRulesDefinition::decl_macro (std::move (rule_name
),
1790 std::move (macro_rules
),
1791 std::move (outer_attrs
),
1796 add_error (Error (t
->get_locus (),
1797 "unexpected token %qs - expecting delimiters "
1798 "(for a declarative macro definiton)",
1799 t
->get_token_description ()));
1804 // Parses a semi-coloned (except for full block) macro invocation item.
1805 template <typename ManagedTokenSource
>
1806 std::unique_ptr
<AST::MacroInvocation
>
1807 Parser
<ManagedTokenSource
>::parse_macro_invocation_semi (
1808 AST::AttrVec outer_attrs
)
1810 location_t macro_locus
= lexer
.peek_token ()->get_locus ();
1811 AST::SimplePath path
= parse_simple_path ();
1813 if (!skip_token (EXCLAM
))
1815 // skip after somewhere?
1819 // save delim type to ensure it is reused later
1820 AST::DelimType delim_type
= AST::PARENS
;
1822 // Map tokens to DelimType
1823 const_TokenPtr t
= lexer
.peek_token ();
1824 switch (t
->get_id ())
1827 delim_type
= AST::PARENS
;
1830 delim_type
= AST::SQUARE
;
1833 delim_type
= AST::CURLY
;
1836 add_error (Error (t
->get_locus (),
1837 "unexpected token %qs - expecting delimiters (for a "
1838 "macro invocation semi body)",
1839 t
->get_token_description ()));
1843 location_t tok_tree_locus
= t
->get_locus ();
1844 lexer
.skip_token ();
1846 // parse actual token trees
1847 std::vector
<std::unique_ptr
<AST::TokenTree
>> token_trees
;
1849 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
1850 token_trees
.push_back (std::move (delim_open
));
1852 t
= lexer
.peek_token ();
1853 // parse token trees until the initial delimiter token is found again
1854 while (!token_id_matches_delims (t
->get_id (), delim_type
))
1856 std::unique_ptr
<AST::TokenTree
> tree
= parse_token_tree ();
1858 if (tree
== nullptr)
1860 Error
error (t
->get_locus (),
1861 "failed to parse token tree for macro invocation semi "
1863 t
->get_token_description ());
1864 add_error (std::move (error
));
1869 token_trees
.push_back (std::move (tree
));
1871 t
= lexer
.peek_token ();
1874 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
1875 token_trees
.push_back (std::move (delim_close
));
1877 AST::DelimTokenTree
delim_tok_tree (delim_type
, std::move (token_trees
),
1879 AST::MacroInvocData
invoc_data (std::move (path
), std::move (delim_tok_tree
));
1881 // parse end delimiters
1882 t
= lexer
.peek_token ();
1883 if (token_id_matches_delims (t
->get_id (), delim_type
))
1885 // tokens match opening delimiter, so skip.
1886 lexer
.skip_token ();
1888 if (delim_type
!= AST::CURLY
)
1890 // skip semicolon at end of non-curly macro invocation semis
1891 if (!skip_token (SEMICOLON
))
1893 // as this is the end, allow recovery (probably) - may change
1895 return AST::MacroInvocation::Regular (std::move (invoc_data
),
1896 std::move (outer_attrs
),
1902 rust_debug ("skipped token is '%s', next token (current peek) is '%s'",
1903 t
->get_token_description (),
1904 lexer
.peek_token ()->get_token_description ());
1906 return AST::MacroInvocation::Regular (std::move (invoc_data
),
1907 std::move (outer_attrs
),
1912 // tokens don't match opening delimiters, so produce error
1913 Error
error (t
->get_locus (),
1914 "unexpected token %qs - expecting closing delimiter %qs "
1915 "(for a macro invocation semi)",
1916 t
->get_token_description (),
1917 (delim_type
== AST::PARENS
1919 : (delim_type
== AST::SQUARE
? "]" : "}")));
1920 add_error (std::move (error
));
1922 /* return empty macro invocation despite possibly parsing mostly valid one
1923 * - TODO is this a good idea? */
1928 // Parses a non-semicoloned macro invocation (i.e. as pattern or expression).
1929 template <typename ManagedTokenSource
>
1930 std::unique_ptr
<AST::MacroInvocation
>
1931 Parser
<ManagedTokenSource
>::parse_macro_invocation (AST::AttrVec outer_attrs
)
1934 AST::SimplePath macro_path
= parse_simple_path ();
1935 if (macro_path
.is_empty ())
1937 Error
error (lexer
.peek_token ()->get_locus (),
1938 "failed to parse macro invocation path");
1939 add_error (std::move (error
));
1945 if (!skip_token (EXCLAM
))
1947 // skip after somewhere?
1951 // parse internal delim token tree
1952 AST::DelimTokenTree delim_tok_tree
= parse_delim_token_tree ();
1954 location_t macro_locus
= macro_path
.get_locus ();
1956 return AST::MacroInvocation::Regular (
1957 AST::MacroInvocData (std::move (macro_path
), std::move (delim_tok_tree
)),
1958 std::move (outer_attrs
), macro_locus
);
1961 // Parses a macro rule definition - does not parse semicolons.
1962 template <typename ManagedTokenSource
>
1964 Parser
<ManagedTokenSource
>::parse_macro_rule ()
1966 location_t locus
= lexer
.peek_token ()->get_locus ();
1968 // parse macro matcher
1969 AST::MacroMatcher matcher
= parse_macro_matcher ();
1971 if (matcher
.is_error ())
1972 return AST::MacroRule::create_error (locus
);
1974 if (!skip_token (MATCH_ARROW
))
1976 // skip after somewhere?
1977 return AST::MacroRule::create_error (locus
);
1980 // parse transcriber (this is just a delim token tree)
1981 location_t token_tree_loc
= lexer
.peek_token ()->get_locus ();
1982 AST::MacroTranscriber
transcriber (parse_delim_token_tree (), token_tree_loc
);
1984 return AST::MacroRule (std::move (matcher
), std::move (transcriber
), locus
);
1987 // Parses a macro matcher (part of a macro rule definition).
1988 template <typename ManagedTokenSource
>
1990 Parser
<ManagedTokenSource
>::parse_macro_matcher ()
1992 // save delim type to ensure it is reused later
1993 AST::DelimType delim_type
= AST::PARENS
;
1996 rust_debug ("begun parsing macro matcher");
1998 // Map tokens to DelimType
1999 const_TokenPtr t
= lexer
.peek_token ();
2000 location_t locus
= t
->get_locus ();
2001 switch (t
->get_id ())
2004 delim_type
= AST::PARENS
;
2007 delim_type
= AST::SQUARE
;
2010 delim_type
= AST::CURLY
;
2015 "unexpected token %qs - expecting delimiters (for a macro matcher)",
2016 t
->get_token_description ()));
2018 return AST::MacroMatcher::create_error (t
->get_locus ());
2020 lexer
.skip_token ();
2022 // parse actual macro matches
2023 std::vector
<std::unique_ptr
<AST::MacroMatch
>> matches
;
2024 // Set of possible preceding macro matches to make sure follow-set
2025 // restrictions are respected.
2026 // TODO: Consider using std::reference_wrapper instead of raw pointers?
2027 std::vector
<const AST::MacroMatch
*> last_matches
;
2029 t
= lexer
.peek_token ();
2030 // parse token trees until the initial delimiter token is found again
2031 while (!token_id_matches_delims (t
->get_id (), delim_type
))
2033 std::unique_ptr
<AST::MacroMatch
> match
= parse_macro_match ();
2035 if (match
== nullptr)
2039 "failed to parse macro match for macro matcher - found %qs",
2040 t
->get_token_description ());
2041 add_error (std::move (error
));
2043 return AST::MacroMatcher::create_error (t
->get_locus ());
2046 if (matches
.size () > 0)
2048 const auto *last_match
= matches
.back ().get ();
2050 // We want to check if we are dealing with a zeroable repetition
2051 bool zeroable
= false;
2052 if (last_match
->get_macro_match_type ()
2053 == AST::MacroMatch::MacroMatchType::Repetition
)
2056 = static_cast<const AST::MacroMatchRepetition
*> (last_match
);
2058 if (repetition
->get_op ()
2059 != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE
)
2064 last_matches
.clear ();
2066 last_matches
.emplace_back (last_match
);
2068 for (auto last
: last_matches
)
2069 if (!is_match_compatible (*last
, *match
))
2070 return AST::MacroMatcher::create_error (
2071 match
->get_match_locus ());
2074 matches
.push_back (std::move (match
));
2077 rust_debug ("pushed back a match in macro matcher");
2079 t
= lexer
.peek_token ();
2082 // parse end delimiters
2083 t
= lexer
.peek_token ();
2084 if (token_id_matches_delims (t
->get_id (), delim_type
))
2086 // tokens match opening delimiter, so skip.
2087 lexer
.skip_token ();
2089 return AST::MacroMatcher (delim_type
, std::move (matches
), locus
);
2093 // tokens don't match opening delimiters, so produce error
2094 Error
error (t
->get_locus (),
2095 "unexpected token %qs - expecting closing delimiter %qs "
2096 "(for a macro matcher)",
2097 t
->get_token_description (),
2098 (delim_type
== AST::PARENS
2100 : (delim_type
== AST::SQUARE
? "]" : "}")));
2101 add_error (std::move (error
));
2103 /* return error macro matcher despite possibly parsing mostly correct one?
2104 * TODO is this the best idea? */
2105 return AST::MacroMatcher::create_error (t
->get_locus ());
2109 // Parses a macro match (syntax match inside a matcher in a macro rule).
2110 template <typename ManagedTokenSource
>
2111 std::unique_ptr
<AST::MacroMatch
>
2112 Parser
<ManagedTokenSource
>::parse_macro_match ()
2114 // branch based on token available
2115 const_TokenPtr t
= lexer
.peek_token ();
2116 switch (t
->get_id ())
2121 // must be macro matcher as delimited
2122 AST::MacroMatcher matcher
= parse_macro_matcher ();
2123 if (matcher
.is_error ())
2125 Error
error (lexer
.peek_token ()->get_locus (),
2126 "failed to parse macro matcher in macro match");
2127 add_error (std::move (error
));
2131 return std::unique_ptr
<AST::MacroMatcher
> (
2132 new AST::MacroMatcher (std::move (matcher
)));
2135 // have to do more lookahead to determine if fragment or repetition
2136 const_TokenPtr t2
= lexer
.peek_token (1);
2137 switch (t2
->get_id ())
2142 return parse_macro_match_fragment ();
2145 return parse_macro_match_repetition ();
2147 if (token_id_is_keyword (t2
->get_id ()) && t2
->get_id () != CRATE
)
2149 // keyword as macro fragment
2150 return parse_macro_match_fragment ();
2154 // error: unrecognised
2157 "unrecognised token combination %<$%s%> at start of "
2158 "macro match - did you mean %<$identifier%> or %<$(%>?",
2159 t2
->get_token_description ()));
2172 "closing delimiters like %qs are not allowed at the start of a macro "
2174 t
->get_token_description ()));
2180 lexer
.skip_token ();
2181 return std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
2185 // Parses a fragment macro match.
2186 template <typename ManagedTokenSource
>
2187 std::unique_ptr
<AST::MacroMatchFragment
>
2188 Parser
<ManagedTokenSource
>::parse_macro_match_fragment ()
2190 location_t fragment_locus
= lexer
.peek_token ()->get_locus ();
2191 skip_token (DOLLAR_SIGN
);
2194 auto identifier
= lexer
.peek_token ();
2195 if (identifier
->get_id () == UNDERSCORE
)
2196 ident
= {Values::Keywords::UNDERSCORE
, identifier
->get_locus ()};
2198 ident
= {identifier
};
2202 Error
error (lexer
.peek_token ()->get_locus (),
2203 "missing identifier in macro match fragment");
2204 add_error (std::move (error
));
2208 skip_token (identifier
->get_id ());
2210 if (!skip_token (COLON
))
2212 // skip after somewhere?
2216 // get MacroFragSpec for macro
2217 const_TokenPtr t
= expect_token (IDENTIFIER
);
2221 AST::MacroFragSpec frag
2222 = AST::MacroFragSpec::get_frag_spec_from_str (t
->get_str ());
2223 if (frag
.is_error ())
2225 Error
error (t
->get_locus (),
2226 "invalid fragment specifier %qs in fragment macro match",
2227 t
->get_str ().c_str ());
2228 add_error (std::move (error
));
2233 return std::unique_ptr
<AST::MacroMatchFragment
> (
2234 new AST::MacroMatchFragment (std::move (ident
), frag
, fragment_locus
));
2237 // Parses a repetition macro match.
2238 template <typename ManagedTokenSource
>
2239 std::unique_ptr
<AST::MacroMatchRepetition
>
2240 Parser
<ManagedTokenSource
>::parse_macro_match_repetition ()
2242 skip_token (DOLLAR_SIGN
);
2243 skip_token (LEFT_PAREN
);
2245 std::vector
<std::unique_ptr
<AST::MacroMatch
>> matches
;
2247 // parse required first macro match
2248 std::unique_ptr
<AST::MacroMatch
> initial_match
= parse_macro_match ();
2249 if (initial_match
== nullptr)
2252 lexer
.peek_token ()->get_locus (),
2253 "could not parse required first macro match in macro match repetition");
2254 add_error (std::move (error
));
2256 // skip after somewhere?
2259 matches
.push_back (std::move (initial_match
));
2261 // parse optional later macro matches
2262 const_TokenPtr t
= lexer
.peek_token ();
2263 while (t
->get_id () != RIGHT_PAREN
)
2265 std::unique_ptr
<AST::MacroMatch
> match
= parse_macro_match ();
2267 if (match
== nullptr)
2269 Error
error (lexer
.peek_token ()->get_locus (),
2270 "failed to parse macro match in macro match repetition");
2271 add_error (std::move (error
));
2276 matches
.push_back (std::move (match
));
2278 t
= lexer
.peek_token ();
2281 if (!skip_token (RIGHT_PAREN
))
2283 // skip after somewhere?
2287 t
= lexer
.peek_token ();
2288 // see if separator token exists
2289 std::unique_ptr
<AST::Token
> separator
= nullptr;
2290 switch (t
->get_id ())
2292 // repetition operators
2303 // separator does not exist, so still null and don't skip token
2306 // separator does exist
2307 separator
= std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
2308 lexer
.skip_token ();
2312 // parse repetition operator
2313 t
= lexer
.peek_token ();
2314 AST::MacroMatchRepetition::MacroRepOp op
= AST::MacroMatchRepetition::NONE
;
2315 switch (t
->get_id ())
2318 op
= AST::MacroMatchRepetition::ANY
;
2319 lexer
.skip_token ();
2322 op
= AST::MacroMatchRepetition::ONE_OR_MORE
;
2323 lexer
.skip_token ();
2326 op
= AST::MacroMatchRepetition::ZERO_OR_ONE
;
2327 lexer
.skip_token ();
2329 if (separator
!= nullptr)
2332 Error (separator
->get_locus (),
2333 "the %<?%> macro repetition operator does not take a "
2335 separator
= nullptr;
2341 Error (t
->get_locus (),
2342 "expected macro repetition operator (%<*%>, %<+%>, or %<?%>) in "
2343 "macro match - found %qs",
2344 t
->get_token_description ()));
2346 // skip after somewhere?
2350 return std::unique_ptr
<AST::MacroMatchRepetition
> (
2351 new AST::MacroMatchRepetition (std::move (matches
), op
,
2352 std::move (separator
), t
->get_locus ()));
2355 /* Parses a visibility syntactical production (i.e. creating a non-default
2357 template <typename ManagedTokenSource
>
2359 Parser
<ManagedTokenSource
>::parse_visibility ()
2361 // check for no visibility
2362 if (lexer
.peek_token ()->get_id () != PUB
)
2364 return AST::Visibility::create_private ();
2367 auto vis_loc
= lexer
.peek_token ()->get_locus ();
2368 lexer
.skip_token ();
2370 // create simple pub visibility if
2371 // - found no parentheses
2372 // - found unit type `()`
2373 if (lexer
.peek_token ()->get_id () != LEFT_PAREN
2374 || lexer
.peek_token (1)->get_id () == RIGHT_PAREN
)
2376 return AST::Visibility::create_public (vis_loc
);
2380 lexer
.skip_token ();
2382 const_TokenPtr t
= lexer
.peek_token ();
2383 auto path_loc
= t
->get_locus ();
2385 switch (t
->get_id ())
2388 lexer
.skip_token ();
2390 skip_token (RIGHT_PAREN
);
2392 return AST::Visibility::create_crate (path_loc
, vis_loc
);
2394 lexer
.skip_token ();
2396 skip_token (RIGHT_PAREN
);
2398 return AST::Visibility::create_self (path_loc
, vis_loc
);
2400 lexer
.skip_token ();
2402 skip_token (RIGHT_PAREN
);
2404 return AST::Visibility::create_super (path_loc
, vis_loc
);
2406 lexer
.skip_token ();
2408 // parse the "in" path as well
2409 AST::SimplePath path
= parse_simple_path ();
2410 if (path
.is_empty ())
2412 Error
error (lexer
.peek_token ()->get_locus (),
2413 "missing path in pub(in path) visibility");
2414 add_error (std::move (error
));
2416 // skip after somewhere?
2417 return AST::Visibility::create_error ();
2420 skip_token (RIGHT_PAREN
);
2422 return AST::Visibility::create_in_path (std::move (path
), vis_loc
);
2425 add_error (Error (t
->get_locus (), "unexpected token %qs in visibility",
2426 t
->get_token_description ()));
2428 lexer
.skip_token ();
2429 return AST::Visibility::create_error ();
2433 // Parses a module - either a bodied module or a module defined in another file.
2434 template <typename ManagedTokenSource
>
2435 std::unique_ptr
<AST::Module
>
2436 Parser
<ManagedTokenSource
>::parse_module (AST::Visibility vis
,
2437 AST::AttrVec outer_attrs
)
2439 location_t locus
= lexer
.peek_token ()->get_locus ();
2441 Unsafety safety
= Unsafety::Normal
;
2442 if (lexer
.peek_token ()->get_id () == UNSAFE
)
2444 safety
= Unsafety::Unsafe
;
2445 skip_token (UNSAFE
);
2450 const_TokenPtr module_name
= expect_token (IDENTIFIER
);
2451 if (module_name
== nullptr)
2455 Identifier name
{module_name
};
2457 const_TokenPtr t
= lexer
.peek_token ();
2459 switch (t
->get_id ())
2462 lexer
.skip_token ();
2464 // Construct an external module
2465 return std::unique_ptr
<AST::Module
> (
2466 new AST::Module (std::move (name
), std::move (vis
),
2467 std::move (outer_attrs
), locus
, safety
,
2468 lexer
.get_filename (), inline_module_stack
));
2470 lexer
.skip_token ();
2472 // parse inner attributes
2473 AST::AttrVec inner_attrs
= parse_inner_attributes ();
2475 std::string default_path
= name
.as_string ();
2477 if (inline_module_stack
.empty ())
2479 std::string filename
= lexer
.get_filename ();
2480 auto slash_idx
= filename
.rfind (file_separator
);
2481 if (slash_idx
== std::string::npos
)
2485 filename
= filename
.substr (slash_idx
);
2488 if (get_file_subdir (filename
, subdir
))
2489 default_path
= subdir
+ file_separator
+ name
.as_string ();
2492 std::string module_path_name
2493 = extract_module_path (inner_attrs
, outer_attrs
, default_path
);
2494 InlineModuleStackScope
scope (*this, std::move (module_path_name
));
2497 std::vector
<std::unique_ptr
<AST::Item
>> items
;
2498 const_TokenPtr tok
= lexer
.peek_token ();
2499 while (tok
->get_id () != RIGHT_CURLY
)
2501 std::unique_ptr
<AST::Item
> item
= parse_item (false);
2502 if (item
== nullptr)
2504 Error
error (tok
->get_locus (),
2505 "failed to parse item in module");
2506 add_error (std::move (error
));
2511 items
.push_back (std::move (item
));
2513 tok
= lexer
.peek_token ();
2516 if (!skip_token (RIGHT_CURLY
))
2522 return std::unique_ptr
<AST::Module
> (
2523 new AST::Module (std::move (name
), locus
, std::move (items
),
2524 std::move (vis
), safety
, std::move (inner_attrs
),
2525 std::move (outer_attrs
))); // module name?
2529 Error (t
->get_locus (),
2530 "unexpected token %qs in module declaration/definition item",
2531 t
->get_token_description ()));
2533 lexer
.skip_token ();
2538 // Parses an extern crate declaration (dependency on external crate)
2539 template <typename ManagedTokenSource
>
2540 std::unique_ptr
<AST::ExternCrate
>
2541 Parser
<ManagedTokenSource
>::parse_extern_crate (AST::Visibility vis
,
2542 AST::AttrVec outer_attrs
)
2544 location_t locus
= lexer
.peek_token ()->get_locus ();
2545 if (!skip_token (EXTERN_KW
))
2547 skip_after_semicolon ();
2551 if (!skip_token (CRATE
))
2553 skip_after_semicolon ();
2557 /* parse crate reference name - this has its own syntactical rule in reference
2558 * but seems to not be used elsewhere, so i'm putting it here */
2559 const_TokenPtr crate_name_tok
= lexer
.peek_token ();
2560 std::string crate_name
;
2562 switch (crate_name_tok
->get_id ())
2565 crate_name
= crate_name_tok
->get_str ();
2566 lexer
.skip_token ();
2569 crate_name
= Values::Keywords::SELF
;
2570 lexer
.skip_token ();
2574 Error (crate_name_tok
->get_locus (),
2575 "expecting crate name (identifier or %<self%>), found %qs",
2576 crate_name_tok
->get_token_description ()));
2578 skip_after_semicolon ();
2582 // don't parse as clause if it doesn't exist
2583 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
2585 lexer
.skip_token ();
2587 return std::unique_ptr
<AST::ExternCrate
> (
2588 new AST::ExternCrate (std::move (crate_name
), std::move (vis
),
2589 std::move (outer_attrs
), locus
));
2592 /* parse as clause - this also has its own syntactical rule in reference and
2593 * also seems to not be used elsewhere, so including here again. */
2594 if (!skip_token (AS
))
2596 skip_after_semicolon ();
2600 const_TokenPtr as_name_tok
= lexer
.peek_token ();
2601 std::string as_name
;
2603 switch (as_name_tok
->get_id ())
2606 as_name
= as_name_tok
->get_str ();
2607 lexer
.skip_token ();
2610 as_name
= Values::Keywords::UNDERSCORE
;
2611 lexer
.skip_token ();
2615 Error (as_name_tok
->get_locus (),
2616 "expecting as clause name (identifier or %<_%>), found %qs",
2617 as_name_tok
->get_token_description ()));
2619 skip_after_semicolon ();
2623 if (!skip_token (SEMICOLON
))
2625 skip_after_semicolon ();
2629 return std::unique_ptr
<AST::ExternCrate
> (
2630 new AST::ExternCrate (std::move (crate_name
), std::move (vis
),
2631 std::move (outer_attrs
), locus
, std::move (as_name
)));
2634 // Parses a use declaration.
2635 template <typename ManagedTokenSource
>
2636 std::unique_ptr
<AST::UseDeclaration
>
2637 Parser
<ManagedTokenSource
>::parse_use_decl (AST::Visibility vis
,
2638 AST::AttrVec outer_attrs
)
2640 location_t locus
= lexer
.peek_token ()->get_locus ();
2641 if (!skip_token (USE
))
2643 skip_after_semicolon ();
2647 // parse use tree, which is required
2648 std::unique_ptr
<AST::UseTree
> use_tree
= parse_use_tree ();
2649 if (use_tree
== nullptr)
2651 Error
error (lexer
.peek_token ()->get_locus (),
2652 "could not parse use tree in use declaration");
2653 add_error (std::move (error
));
2655 skip_after_semicolon ();
2659 if (!skip_token (SEMICOLON
))
2661 skip_after_semicolon ();
2665 return std::unique_ptr
<AST::UseDeclaration
> (
2666 new AST::UseDeclaration (std::move (use_tree
), std::move (vis
),
2667 std::move (outer_attrs
), locus
));
2670 // Parses a use tree (which can be recursive and is actually a base class).
2671 template <typename ManagedTokenSource
>
2672 std::unique_ptr
<AST::UseTree
>
2673 Parser
<ManagedTokenSource
>::parse_use_tree ()
2675 /* potential syntax definitions in attempt to get algorithm:
2677 * <- SimplePath :: *
2680 * Nested tree thing:
2681 * <- SimplePath :: { COMPLICATED_INNER_TREE_THING }
2682 * <- :: COMPLICATED_INNER_TREE_THING }
2683 * <- { COMPLICATED_INNER_TREE_THING }
2685 * <- SimplePath as IDENTIFIER
2686 * <- SimplePath as _
2690 /* current plan of attack: try to parse SimplePath first - if fails, one of
2691 * top two then try parse :: - if fails, one of top two. Next is deciding
2692 * character for top two. */
2694 /* Thus, parsing smaller parts of use tree may require feeding into function
2695 * via parameters (or could handle all in this single function because other
2696 * use tree types aren't recognised as separate in the spec) */
2698 // TODO: I think this function is too complex, probably should split it
2700 location_t locus
= lexer
.peek_token ()->get_locus ();
2702 // bool has_path = false;
2703 AST::SimplePath path
= parse_simple_path ();
2705 if (path
.is_empty ())
2707 // has no path, so must be glob or nested tree UseTree type
2709 bool is_global
= false;
2711 // check for global scope resolution operator
2712 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
)
2714 lexer
.skip_token ();
2718 const_TokenPtr t
= lexer
.peek_token ();
2719 switch (t
->get_id ())
2722 // glob UseTree type
2723 lexer
.skip_token ();
2726 return std::unique_ptr
<AST::UseTreeGlob
> (
2727 new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL
,
2728 AST::SimplePath::create_empty (), locus
));
2730 return std::unique_ptr
<AST::UseTreeGlob
> (
2731 new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH
,
2732 AST::SimplePath::create_empty (), locus
));
2734 // nested tree UseTree type
2735 lexer
.skip_token ();
2737 std::vector
<std::unique_ptr
<AST::UseTree
>> use_trees
;
2739 const_TokenPtr t
= lexer
.peek_token ();
2740 while (t
->get_id () != RIGHT_CURLY
)
2742 std::unique_ptr
<AST::UseTree
> use_tree
= parse_use_tree ();
2743 if (use_tree
== nullptr)
2748 use_trees
.push_back (std::move (use_tree
));
2750 if (lexer
.peek_token ()->get_id () != COMMA
)
2753 lexer
.skip_token ();
2754 t
= lexer
.peek_token ();
2757 // skip end curly delimiter
2758 if (!skip_token (RIGHT_CURLY
))
2760 // skip after somewhere?
2765 return std::unique_ptr
<AST::UseTreeList
> (
2766 new AST::UseTreeList (AST::UseTreeList::GLOBAL
,
2767 AST::SimplePath::create_empty (),
2768 std::move (use_trees
), locus
));
2770 return std::unique_ptr
<AST::UseTreeList
> (
2771 new AST::UseTreeList (AST::UseTreeList::NO_PATH
,
2772 AST::SimplePath::create_empty (),
2773 std::move (use_trees
), locus
));
2776 // this is not allowed
2779 "use declaration with rebind %<as%> requires a valid simple path - "
2782 skip_after_semicolon ();
2785 add_error (Error (t
->get_locus (),
2786 "unexpected token %qs in use tree with "
2787 "no valid simple path (i.e. list"
2788 " or glob use tree)",
2789 t
->get_token_description ()));
2791 skip_after_semicolon ();
2797 /* Due to aforementioned implementation issues, the trailing :: token is
2798 * consumed by the path, so it can not be used as a disambiguator.
2799 * NOPE, not true anymore - TODO what are the consequences of this? */
2801 const_TokenPtr t
= lexer
.peek_token ();
2802 switch (t
->get_id ())
2805 // glob UseTree type
2806 lexer
.skip_token ();
2808 return std::unique_ptr
<AST::UseTreeGlob
> (
2809 new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED
,
2810 std::move (path
), locus
));
2812 // nested tree UseTree type
2813 lexer
.skip_token ();
2815 std::vector
<std::unique_ptr
<AST::UseTree
>> use_trees
;
2817 // TODO: think of better control structure
2818 const_TokenPtr t
= lexer
.peek_token ();
2819 while (t
->get_id () != RIGHT_CURLY
)
2821 std::unique_ptr
<AST::UseTree
> use_tree
= parse_use_tree ();
2822 if (use_tree
== nullptr)
2827 use_trees
.push_back (std::move (use_tree
));
2829 if (lexer
.peek_token ()->get_id () != COMMA
)
2832 lexer
.skip_token ();
2833 t
= lexer
.peek_token ();
2836 // skip end curly delimiter
2837 if (!skip_token (RIGHT_CURLY
))
2839 // skip after somewhere?
2843 return std::unique_ptr
<AST::UseTreeList
> (
2844 new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED
,
2845 std::move (path
), std::move (use_trees
),
2849 // rebind UseTree type
2850 lexer
.skip_token ();
2852 const_TokenPtr t
= lexer
.peek_token ();
2853 switch (t
->get_id ())
2857 lexer
.skip_token ();
2859 return std::unique_ptr
<AST::UseTreeRebind
> (
2860 new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER
,
2861 std::move (path
), locus
, t
));
2864 lexer
.skip_token ();
2866 return std::unique_ptr
<AST::UseTreeRebind
> (
2867 new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD
,
2868 std::move (path
), locus
,
2869 {Values::Keywords::UNDERSCORE
,
2874 "unexpected token %qs in use tree with as clause - expected "
2875 "identifier or %<_%>",
2876 t
->get_token_description ()));
2878 skip_after_semicolon ();
2883 // rebind UseTree type without rebinding - path only
2885 // don't skip semicolon - handled in parse_use_tree
2886 // lexer.skip_token();
2888 return std::unique_ptr
<AST::UseTreeRebind
> (
2889 new AST::UseTreeRebind (AST::UseTreeRebind::NONE
, std::move (path
),
2893 // this may occur in recursive calls - assume it is ok and ignore it
2894 return std::unique_ptr
<AST::UseTreeRebind
> (
2895 new AST::UseTreeRebind (AST::UseTreeRebind::NONE
, std::move (path
),
2898 add_error (Error (t
->get_locus (),
2899 "unexpected token %qs in use tree with valid path",
2900 t
->get_token_description ()));
2902 // skip_after_semicolon();
2908 // Parses a function (not a method).
2909 template <typename ManagedTokenSource
>
2910 std::unique_ptr
<AST::Function
>
2911 Parser
<ManagedTokenSource
>::parse_function (AST::Visibility vis
,
2912 AST::AttrVec outer_attrs
,
2915 location_t locus
= lexer
.peek_token ()->get_locus ();
2916 // Get qualifiers for function if they exist
2917 AST::FunctionQualifiers qualifiers
= parse_function_qualifiers ();
2921 // Save function name token
2922 const_TokenPtr function_name_tok
= expect_token (IDENTIFIER
);
2923 if (function_name_tok
== nullptr)
2925 skip_after_next_block ();
2928 Identifier function_name
{function_name_tok
};
2930 // parse generic params - if exist
2931 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
2932 = parse_generic_params_in_angles ();
2934 if (!skip_token (LEFT_PAREN
))
2936 Error
error (lexer
.peek_token ()->get_locus (),
2937 "function declaration missing opening parentheses before "
2939 add_error (std::move (error
));
2941 skip_after_next_block ();
2945 auto initial_param
= parse_self_param ();
2947 if (!initial_param
.has_value ()
2948 && initial_param
.error () != ParseSelfError::NOT_SELF
)
2951 if (initial_param
.has_value () && lexer
.peek_token ()->get_id () == COMMA
)
2954 // parse function parameters (only if next token isn't right paren)
2955 std::vector
<std::unique_ptr
<AST::Param
>> function_params
;
2957 if (lexer
.peek_token ()->get_id () != RIGHT_PAREN
)
2959 = parse_function_params ([] (TokenId id
) { return id
== RIGHT_PAREN
; });
2961 if (initial_param
.has_value ())
2962 function_params
.insert (function_params
.begin (),
2963 std::move (*initial_param
));
2965 if (!skip_token (RIGHT_PAREN
))
2967 Error
error (lexer
.peek_token ()->get_locus (),
2968 "function declaration missing closing parentheses after "
2970 add_error (std::move (error
));
2972 skip_after_next_block ();
2976 // parse function return type - if exists
2977 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
2979 // parse where clause - if exists
2980 AST::WhereClause where_clause
= parse_where_clause ();
2982 tl::optional
<std::unique_ptr
<AST::BlockExpr
>> body
= tl::nullopt
;
2983 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
2984 lexer
.skip_token ();
2987 std::unique_ptr
<AST::BlockExpr
> block_expr
= parse_block_expr ();
2988 if (block_expr
!= nullptr)
2989 body
= std::move (block_expr
);
2992 return std::unique_ptr
<AST::Function
> (
2993 new AST::Function (std::move (function_name
), std::move (qualifiers
),
2994 std::move (generic_params
), std::move (function_params
),
2995 std::move (return_type
), std::move (where_clause
),
2996 std::move (body
), std::move (vis
),
2997 std::move (outer_attrs
), locus
, false, is_external
));
3000 // Parses function or method qualifiers (i.e. const, unsafe, and extern).
3001 template <typename ManagedTokenSource
>
3002 AST::FunctionQualifiers
3003 Parser
<ManagedTokenSource
>::parse_function_qualifiers ()
3005 Async async_status
= Async::No
;
3006 Const const_status
= Const::No
;
3007 Unsafety unsafe_status
= Unsafety::Normal
;
3008 bool has_extern
= false;
3013 // Check in order of const, unsafe, then extern
3014 for (int i
= 0; i
< 2; i
++)
3016 t
= lexer
.peek_token ();
3017 locus
= t
->get_locus ();
3019 switch (t
->get_id ())
3022 lexer
.skip_token ();
3023 const_status
= Const::Yes
;
3026 lexer
.skip_token ();
3027 async_status
= Async::Yes
;
3030 // const status is still none
3035 if (lexer
.peek_token ()->get_id () == UNSAFE
)
3037 lexer
.skip_token ();
3038 unsafe_status
= Unsafety::Unsafe
;
3041 if (lexer
.peek_token ()->get_id () == EXTERN_KW
)
3043 lexer
.skip_token ();
3046 // detect optional abi name
3047 const_TokenPtr next_tok
= lexer
.peek_token ();
3048 if (next_tok
->get_id () == STRING_LITERAL
)
3050 lexer
.skip_token ();
3051 abi
= next_tok
->get_str ();
3055 return AST::FunctionQualifiers (locus
, async_status
, const_status
,
3056 unsafe_status
, has_extern
, std::move (abi
));
3059 // Parses generic (lifetime or type) params inside angle brackets (optional).
3060 template <typename ManagedTokenSource
>
3061 std::vector
<std::unique_ptr
<AST::GenericParam
>>
3062 Parser
<ManagedTokenSource
>::parse_generic_params_in_angles ()
3064 if (lexer
.peek_token ()->get_id () != LEFT_ANGLE
)
3066 // seems to be no generic params, so exit with empty vector
3067 return std::vector
<std::unique_ptr
<AST::GenericParam
>> ();
3069 lexer
.skip_token ();
3072 rust_debug ("skipped left angle in generic param");
3074 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
3075 = parse_generic_params (is_right_angle_tok
);
3078 rust_debug ("finished parsing actual generic params (i.e. inside angles)");
3080 if (!skip_generics_right_angle ())
3083 rust_debug ("failed to skip generics right angle - returning empty "
3086 return std::vector
<std::unique_ptr
<AST::GenericParam
>> ();
3089 return generic_params
;
3092 template <typename ManagedTokenSource
>
3093 template <typename EndTokenPred
>
3094 std::unique_ptr
<AST::GenericParam
>
3095 Parser
<ManagedTokenSource
>::parse_generic_param (EndTokenPred is_end_token
)
3097 auto outer_attrs
= parse_outer_attributes ();
3098 std::unique_ptr
<AST::GenericParam
> param
;
3099 auto token
= lexer
.peek_token ();
3101 switch (token
->get_id ())
3104 auto lifetime
= parse_lifetime (false);
3108 token
->get_locus (),
3109 "failed to parse lifetime in generic parameter list");
3113 std::vector
<AST::Lifetime
> lifetime_bounds
;
3114 if (lexer
.peek_token ()->get_id () == COLON
)
3116 lexer
.skip_token ();
3117 // parse required bounds
3119 = parse_lifetime_bounds ([is_end_token
] (TokenId id
) {
3120 return is_end_token (id
) || id
== COMMA
;
3124 param
= std::unique_ptr
<AST::LifetimeParam
> (new AST::LifetimeParam (
3125 std::move (lifetime
.value ()), std::move (lifetime_bounds
),
3126 std::move (outer_attrs
), token
->get_locus ()));
3130 auto type_ident
= token
->get_str ();
3131 lexer
.skip_token ();
3133 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
;
3134 if (lexer
.peek_token ()->get_id () == COLON
)
3136 lexer
.skip_token ();
3138 // parse optional type param bounds
3139 type_param_bounds
= parse_type_param_bounds ();
3142 std::unique_ptr
<AST::Type
> type
= nullptr;
3143 if (lexer
.peek_token ()->get_id () == EQUAL
)
3145 lexer
.skip_token ();
3147 // parse required type
3148 type
= parse_type ();
3152 lexer
.peek_token ()->get_locus (),
3153 "failed to parse type in type param in generic params");
3158 param
= std::unique_ptr
<AST::TypeParam
> (
3159 new AST::TypeParam (std::move (type_ident
), token
->get_locus (),
3160 std::move (type_param_bounds
), std::move (type
),
3161 std::move (outer_attrs
)));
3165 lexer
.skip_token ();
3167 auto name_token
= expect_token (IDENTIFIER
);
3169 if (!name_token
|| !expect_token (COLON
))
3172 auto type
= parse_type ();
3176 // optional default value
3177 tl::optional
<AST::GenericArg
> default_expr
= tl::nullopt
;
3178 if (lexer
.peek_token ()->get_id () == EQUAL
)
3180 lexer
.skip_token ();
3181 auto tok
= lexer
.peek_token ();
3182 default_expr
= parse_generic_arg ();
3186 rust_error_at (tok
->get_locus (),
3187 "invalid token for start of default value for "
3188 "const generic parameter: expected %<block%>, "
3189 "%<identifier%> or %<literal%>, got %qs",
3190 token_id_to_str (tok
->get_id ()));
3194 // At this point, we *know* that we are parsing a const
3196 if (default_expr
.value ().get_kind ()
3197 == AST::GenericArg::Kind::Either
)
3198 default_expr
= default_expr
.value ().disambiguate_to_const ();
3201 param
= std::unique_ptr
<AST::ConstGenericParam
> (
3202 new AST::ConstGenericParam (name_token
->get_str (), std::move (type
),
3203 default_expr
, std::move (outer_attrs
),
3204 token
->get_locus ()));
3209 // FIXME: Can we clean this last call with a method call?
3210 rust_error_at (token
->get_locus (),
3211 "unexpected token when parsing generic parameters: %qs",
3212 token
->as_string ().c_str ());
3219 /* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost
3220 * always parse_generic_params_in_angles is what is wanted. */
3221 template <typename ManagedTokenSource
>
3222 template <typename EndTokenPred
>
3223 std::vector
<std::unique_ptr
<AST::GenericParam
>>
3224 Parser
<ManagedTokenSource
>::parse_generic_params (EndTokenPred is_end_token
)
3226 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
;
3228 /* can't parse lifetime and type params separately due to lookahead issues
3229 * thus, parse them all here */
3231 /* HACK: used to retain attribute data if a lifetime param is tentatively
3232 * parsed but it turns out to be type param */
3233 AST::Attribute parsed_outer_attr
= AST::Attribute::create_empty ();
3235 // Did we parse a generic type param yet
3236 auto type_seen
= false;
3237 // Did the user write a lifetime parameter after a type one
3238 auto order_error
= false;
3240 // parse lifetime params
3241 while (!is_end_token (lexer
.peek_token ()->get_id ()))
3243 auto param
= parse_generic_param (is_end_token
);
3246 // TODO: Handle `Const` here as well if necessary
3247 if (param
->get_kind () == AST::GenericParam::Kind::Type
)
3249 else if (param
->get_kind () == AST::GenericParam::Kind::Lifetime
3253 generic_params
.emplace_back (std::move (param
));
3254 maybe_skip_token (COMMA
);
3260 // FIXME: Add reordering hint
3263 Error
error (generic_params
.front ()->get_locus (),
3264 "invalid order for generic parameters: lifetime parameters "
3265 "must be declared prior to type and const parameters");
3266 add_error (std::move (error
));
3269 generic_params
.shrink_to_fit ();
3270 return generic_params
;
3273 /* Parses lifetime generic parameters (pointers). Will also consume any
3274 * trailing comma. No extra checks for end token. */
3275 template <typename ManagedTokenSource
>
3276 std::vector
<std::unique_ptr
<AST::LifetimeParam
>>
3277 Parser
<ManagedTokenSource
>::parse_lifetime_params ()
3279 std::vector
<std::unique_ptr
<AST::LifetimeParam
>> lifetime_params
;
3281 while (lexer
.peek_token ()->get_id () != END_OF_FILE
)
3283 auto lifetime_param
= parse_lifetime_param ();
3285 if (!lifetime_param
)
3287 // can't treat as error as only way to get out with trailing comma
3291 lifetime_params
.push_back (std::unique_ptr
<AST::LifetimeParam
> (
3292 new AST::LifetimeParam (std::move (lifetime_param
.value ()))));
3294 if (lexer
.peek_token ()->get_id () != COMMA
)
3297 // skip commas, including trailing commas
3298 lexer
.skip_token ();
3301 lifetime_params
.shrink_to_fit ();
3303 return lifetime_params
;
3306 /* Parses lifetime generic parameters (pointers). Will also consume any
3307 * trailing comma. Has extra is_end_token predicate checking. */
3308 template <typename ManagedTokenSource
>
3309 template <typename EndTokenPred
>
3310 std::vector
<std::unique_ptr
<AST::LifetimeParam
>>
3311 Parser
<ManagedTokenSource
>::parse_lifetime_params (EndTokenPred is_end_token
)
3313 std::vector
<std::unique_ptr
<AST::LifetimeParam
>> lifetime_params
;
3315 // if end_token is not specified, it defaults to EOF, so should work fine
3316 while (!is_end_token (lexer
.peek_token ()->get_id ()))
3318 auto lifetime_param
= parse_lifetime_param ();
3320 if (!lifetime_param
)
3322 /* TODO: is it worth throwing away all lifetime params just because
3324 Error
error (lexer
.peek_token ()->get_locus (),
3325 "failed to parse lifetime param in lifetime params");
3326 add_error (std::move (error
));
3331 lifetime_params
.push_back (std::unique_ptr
<AST::LifetimeParam
> (
3332 new AST::LifetimeParam (std::move (lifetime_param
))));
3334 if (lexer
.peek_token ()->get_id () != COMMA
)
3337 // skip commas, including trailing commas
3338 lexer
.skip_token ();
3341 lifetime_params
.shrink_to_fit ();
3343 return lifetime_params
;
3346 /* Parses lifetime generic parameters (objects). Will also consume any
3347 * trailing comma. No extra checks for end token.
3348 * TODO: is this best solution? implements most of the same algorithm. */
3349 template <typename ManagedTokenSource
>
3350 std::vector
<AST::LifetimeParam
>
3351 Parser
<ManagedTokenSource
>::parse_lifetime_params_objs ()
3353 std::vector
<AST::LifetimeParam
> lifetime_params
;
3355 // bad control structure as end token cannot be guaranteed
3358 auto lifetime_param
= parse_lifetime_param ();
3360 if (!lifetime_param
)
3362 // not an error as only way to exit if trailing comma
3366 lifetime_params
.push_back (std::move (lifetime_param
));
3368 if (lexer
.peek_token ()->get_id () != COMMA
)
3371 // skip commas, including trailing commas
3372 lexer
.skip_token ();
3375 lifetime_params
.shrink_to_fit ();
3377 return lifetime_params
;
3380 /* Parses lifetime generic parameters (objects). Will also consume any
3381 * trailing comma. Has extra is_end_token predicate checking.
3382 * TODO: is this best solution? implements most of the same algorithm. */
3383 template <typename ManagedTokenSource
>
3384 template <typename EndTokenPred
>
3385 std::vector
<AST::LifetimeParam
>
3386 Parser
<ManagedTokenSource
>::parse_lifetime_params_objs (
3387 EndTokenPred is_end_token
)
3389 std::vector
<AST::LifetimeParam
> lifetime_params
;
3391 while (!is_end_token (lexer
.peek_token ()->get_id ()))
3393 auto lifetime_param
= parse_lifetime_param ();
3395 if (!lifetime_param
)
3397 /* TODO: is it worth throwing away all lifetime params just because
3399 Error
error (lexer
.peek_token ()->get_locus (),
3400 "failed to parse lifetime param in lifetime params");
3401 add_error (std::move (error
));
3406 lifetime_params
.push_back (std::move (lifetime_param
.value ()));
3408 if (lexer
.peek_token ()->get_id () != COMMA
)
3411 // skip commas, including trailing commas
3412 lexer
.skip_token ();
3415 lifetime_params
.shrink_to_fit ();
3417 return lifetime_params
;
3420 /* Parses a sequence of a certain grammar rule in object form (not pointer or
3421 * smart pointer), delimited by commas and ending when 'is_end_token' is
3422 * satisfied (templated). Will also consume any trailing comma.
3423 * FIXME: this cannot be used due to member function pointer problems (i.e.
3424 * parsing_function cannot be specified properly) */
3425 template <typename ManagedTokenSource
>
3426 template <typename ParseFunction
, typename EndTokenPred
>
3428 Parser
<ManagedTokenSource
>::parse_non_ptr_sequence (
3429 ParseFunction parsing_function
, EndTokenPred is_end_token
,
3430 std::string error_msg
) -> std::vector
<decltype (parsing_function ())>
3432 std::vector
<decltype (parsing_function ())> params
;
3434 while (!is_end_token (lexer
.peek_token ()->get_id ()))
3436 auto param
= parsing_function ();
3438 if (param
.is_error ())
3440 // TODO: is it worth throwing away all params just because one
3442 Error
error (lexer
.peek_token ()->get_locus (),
3443 std::move (error_msg
));
3444 add_error (std::move (error
));
3449 params
.push_back (std::move (param
));
3451 if (lexer
.peek_token ()->get_id () != COMMA
)
3454 // skip commas, including trailing commas
3455 lexer
.skip_token ();
3458 params
.shrink_to_fit ();
3463 /* Parses a single lifetime generic parameter (not including comma). */
3464 template <typename ManagedTokenSource
>
3465 tl::expected
<AST::LifetimeParam
, ParseLifetimeParamError
>
3466 Parser
<ManagedTokenSource
>::parse_lifetime_param ()
3468 // parse outer attributes, which are optional and may not exist
3469 auto outer_attrs
= parse_outer_attributes ();
3471 // save lifetime token - required
3472 const_TokenPtr lifetime_tok
= lexer
.peek_token ();
3473 if (lifetime_tok
->get_id () != LIFETIME
)
3475 // if lifetime is missing, must not be a lifetime param, so return error
3476 return tl::make_unexpected
<ParseLifetimeParamError
> ({});
3478 lexer
.skip_token ();
3479 AST::Lifetime
lifetime (AST::Lifetime::NAMED
, lifetime_tok
->get_str (),
3480 lifetime_tok
->get_locus ());
3482 // parse lifetime bounds, if it exists
3483 std::vector
<AST::Lifetime
> lifetime_bounds
;
3484 if (lexer
.peek_token ()->get_id () == COLON
)
3486 // parse lifetime bounds
3487 lifetime_bounds
= parse_lifetime_bounds ();
3488 // TODO: have end token passed in?
3491 return AST::LifetimeParam (std::move (lifetime
), std::move (lifetime_bounds
),
3492 std::move (outer_attrs
),
3493 lifetime_tok
->get_locus ());
3496 // Parses type generic parameters. Will also consume any trailing comma.
3497 template <typename ManagedTokenSource
>
3498 std::vector
<std::unique_ptr
<AST::TypeParam
>>
3499 Parser
<ManagedTokenSource
>::parse_type_params ()
3501 std::vector
<std::unique_ptr
<AST::TypeParam
>> type_params
;
3503 // infinite loop with break on failure as no info on ending token
3506 std::unique_ptr
<AST::TypeParam
> type_param
= parse_type_param ();
3508 if (type_param
== nullptr)
3510 // break if fails to parse
3514 type_params
.push_back (std::move (type_param
));
3516 if (lexer
.peek_token ()->get_id () != COMMA
)
3519 // skip commas, including trailing commas
3520 lexer
.skip_token ();
3523 type_params
.shrink_to_fit ();
3527 // Parses type generic parameters. Will also consume any trailing comma.
3528 template <typename ManagedTokenSource
>
3529 template <typename EndTokenPred
>
3530 std::vector
<std::unique_ptr
<AST::TypeParam
>>
3531 Parser
<ManagedTokenSource
>::parse_type_params (EndTokenPred is_end_token
)
3533 std::vector
<std::unique_ptr
<AST::TypeParam
>> type_params
;
3535 while (!is_end_token (lexer
.peek_token ()->get_id ()))
3537 std::unique_ptr
<AST::TypeParam
> type_param
= parse_type_param ();
3539 if (type_param
== nullptr)
3541 Error
error (lexer
.peek_token ()->get_locus (),
3542 "failed to parse type param in type params");
3543 add_error (std::move (error
));
3548 type_params
.push_back (std::move (type_param
));
3550 if (lexer
.peek_token ()->get_id () != COMMA
)
3553 // skip commas, including trailing commas
3554 lexer
.skip_token ();
3557 type_params
.shrink_to_fit ();
3559 /* TODO: this shares most code with parse_lifetime_params - good place to
3560 * use template (i.e. parse_non_ptr_sequence if doable) */
3563 /* Parses a single type (generic) parameter, not including commas. May change
3564 * to return value. */
3565 template <typename ManagedTokenSource
>
3566 std::unique_ptr
<AST::TypeParam
>
3567 Parser
<ManagedTokenSource
>::parse_type_param ()
3569 // parse outer attributes, which are optional and may not exist
3570 auto outer_attrs
= parse_outer_attributes ();
3572 const_TokenPtr identifier_tok
= lexer
.peek_token ();
3573 if (identifier_tok
->get_id () != IDENTIFIER
)
3575 // return null as type param can't exist without this required
3579 Identifier ident
{identifier_tok
};
3580 lexer
.skip_token ();
3582 // parse type param bounds (if they exist)
3583 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
;
3584 if (lexer
.peek_token ()->get_id () == COLON
)
3586 lexer
.skip_token ();
3588 // parse type param bounds, which may or may not exist
3589 type_param_bounds
= parse_type_param_bounds ();
3592 // parse type (if it exists)
3593 std::unique_ptr
<AST::Type
> type
= nullptr;
3594 if (lexer
.peek_token ()->get_id () == EQUAL
)
3596 lexer
.skip_token ();
3598 // parse type (now required)
3599 type
= parse_type ();
3600 if (type
== nullptr)
3602 Error
error (lexer
.peek_token ()->get_locus (),
3603 "failed to parse type in type param");
3604 add_error (std::move (error
));
3610 return std::unique_ptr
<AST::TypeParam
> (
3611 new AST::TypeParam (std::move (ident
), identifier_tok
->get_locus (),
3612 std::move (type_param_bounds
), std::move (type
),
3613 std::move (outer_attrs
)));
3616 /* Parses regular (i.e. non-generic) parameters in functions or methods. Also
3617 * has end token handling. */
3618 template <typename ManagedTokenSource
>
3619 template <typename EndTokenPred
>
3620 std::vector
<std::unique_ptr
<AST::Param
>>
3621 Parser
<ManagedTokenSource
>::parse_function_params (EndTokenPred is_end_token
)
3623 std::vector
<std::unique_ptr
<AST::Param
>> params
;
3625 if (is_end_token (lexer
.peek_token ()->get_id ()))
3628 auto initial_param
= parse_function_param ();
3630 // Return empty parameter list if no parameter there
3631 if (initial_param
== nullptr)
3633 // TODO: is this an error?
3637 params
.push_back (std::move (initial_param
));
3639 // maybe think of a better control structure here - do-while with an initial
3640 // error state? basically, loop through parameter list until can't find any
3642 const_TokenPtr t
= lexer
.peek_token ();
3643 while (t
->get_id () == COMMA
)
3645 // skip comma if applies
3646 lexer
.skip_token ();
3648 // TODO: strictly speaking, shouldn't there be no trailing comma?
3649 if (is_end_token (lexer
.peek_token ()->get_id ()))
3652 // now, as right paren would break, function param is required
3653 auto param
= parse_function_param ();
3654 if (param
== nullptr)
3656 Error
error (lexer
.peek_token ()->get_locus (),
3657 "failed to parse function param (in function params)");
3658 add_error (std::move (error
));
3661 return std::vector
<std::unique_ptr
<AST::Param
>> ();
3664 params
.push_back (std::move (param
));
3666 t
= lexer
.peek_token ();
3669 params
.shrink_to_fit ();
3673 /* Parses a single regular (i.e. non-generic) parameter in a function or
3674 * method, i.e. the "name: type" bit. Also handles it not existing. */
3675 template <typename ManagedTokenSource
>
3676 std::unique_ptr
<AST::Param
>
3677 Parser
<ManagedTokenSource
>::parse_function_param ()
3679 // parse outer attributes if they exist
3680 AST::AttrVec outer_attrs
= parse_outer_attributes ();
3682 // TODO: should saved location be at start of outer attributes or pattern?
3683 location_t locus
= lexer
.peek_token ()->get_locus ();
3685 if (lexer
.peek_token ()->get_id () == ELLIPSIS
) // Unnamed variadic
3687 lexer
.skip_token (); // Skip ellipsis
3688 return std::make_unique
<AST::VariadicParam
> (
3689 AST::VariadicParam (std::move (outer_attrs
), locus
));
3692 std::unique_ptr
<AST::Pattern
> param_pattern
= parse_pattern ();
3694 // create error function param if it doesn't exist
3695 if (param_pattern
== nullptr)
3697 // skip after something
3701 if (!skip_token (COLON
))
3703 // skip after something
3707 if (lexer
.peek_token ()->get_id () == ELLIPSIS
) // Named variadic
3709 lexer
.skip_token (); // Skip ellipsis
3710 return std::make_unique
<AST::VariadicParam
> (
3711 AST::VariadicParam (std::move (param_pattern
), std::move (outer_attrs
),
3716 std::unique_ptr
<AST::Type
> param_type
= parse_type ();
3717 if (param_type
== nullptr)
3721 return std::make_unique
<AST::FunctionParam
> (
3722 AST::FunctionParam (std::move (param_pattern
), std::move (param_type
),
3723 std::move (outer_attrs
), locus
));
3727 /* Parses a function or method return type syntactical construction. Also
3728 * handles a function return type not existing. */
3729 template <typename ManagedTokenSource
>
3730 std::unique_ptr
<AST::Type
>
3731 Parser
<ManagedTokenSource
>::parse_function_return_type ()
3733 if (lexer
.peek_token ()->get_id () != RETURN_TYPE
)
3736 // skip return type, as it now obviously exists
3737 lexer
.skip_token ();
3739 std::unique_ptr
<AST::Type
> type
= parse_type ();
3744 /* Parses a "where clause" (in a function, struct, method, etc.). Also handles
3745 * a where clause not existing, in which it will return
3746 * WhereClause::create_empty(), which can be checked via
3747 * WhereClause::is_empty(). */
3748 template <typename ManagedTokenSource
>
3750 Parser
<ManagedTokenSource
>::parse_where_clause ()
3752 const_TokenPtr where_tok
= lexer
.peek_token ();
3753 if (where_tok
->get_id () != WHERE
)
3755 // where clause doesn't exist, so create empty one
3756 return AST::WhereClause::create_empty ();
3759 lexer
.skip_token ();
3761 /* parse where clause items - this is not a separate rule in the reference
3762 * so won't be here */
3763 std::vector
<std::unique_ptr
<AST::WhereClauseItem
>> where_clause_items
;
3765 std::vector
<AST::LifetimeParam
> for_lifetimes
;
3766 if (lexer
.peek_token ()->get_id () == FOR
)
3767 for_lifetimes
= parse_for_lifetimes ();
3769 /* HACK: where clauses end with a right curly or semicolon or equals in all
3771 const_TokenPtr t
= lexer
.peek_token ();
3772 while (t
->get_id () != LEFT_CURLY
&& t
->get_id () != SEMICOLON
3773 && t
->get_id () != EQUAL
)
3775 std::unique_ptr
<AST::WhereClauseItem
> where_clause_item
3776 = parse_where_clause_item (for_lifetimes
);
3778 if (where_clause_item
== nullptr)
3780 Error
error (t
->get_locus (), "failed to parse where clause item");
3781 add_error (std::move (error
));
3783 return AST::WhereClause::create_empty ();
3786 where_clause_items
.push_back (std::move (where_clause_item
));
3788 // also skip comma if it exists
3789 if (lexer
.peek_token ()->get_id () != COMMA
)
3792 lexer
.skip_token ();
3793 t
= lexer
.peek_token ();
3796 where_clause_items
.shrink_to_fit ();
3797 return AST::WhereClause (std::move (where_clause_items
));
3800 /* Parses a where clause item (lifetime or type bound). Does not parse any
3802 template <typename ManagedTokenSource
>
3803 std::unique_ptr
<AST::WhereClauseItem
>
3804 Parser
<ManagedTokenSource
>::parse_where_clause_item (
3805 const std::vector
<AST::LifetimeParam
> &outer_for_lifetimes
)
3807 // shitty cheat way of determining lifetime or type bound - test for
3809 const_TokenPtr t
= lexer
.peek_token ();
3811 if (t
->get_id () == LIFETIME
)
3812 return parse_lifetime_where_clause_item ();
3814 return parse_type_bound_where_clause_item (outer_for_lifetimes
);
3817 // Parses a lifetime where clause item.
3818 template <typename ManagedTokenSource
>
3819 std::unique_ptr
<AST::LifetimeWhereClauseItem
>
3820 Parser
<ManagedTokenSource
>::parse_lifetime_where_clause_item ()
3822 auto parsed_lifetime
= parse_lifetime (false);
3823 if (!parsed_lifetime
)
3825 // TODO: error here?
3828 auto lifetime
= parsed_lifetime
.value ();
3830 if (!skip_token (COLON
))
3832 // TODO: skip after somewhere
3836 std::vector
<AST::Lifetime
> lifetime_bounds
= parse_lifetime_bounds ();
3837 // TODO: have end token passed in?
3839 location_t locus
= lifetime
.get_locus ();
3841 return std::unique_ptr
<AST::LifetimeWhereClauseItem
> (
3842 new AST::LifetimeWhereClauseItem (std::move (lifetime
),
3843 std::move (lifetime_bounds
), locus
));
3846 // Parses a type bound where clause item.
3847 template <typename ManagedTokenSource
>
3848 std::unique_ptr
<AST::TypeBoundWhereClauseItem
>
3849 Parser
<ManagedTokenSource
>::parse_type_bound_where_clause_item (
3850 const std::vector
<AST::LifetimeParam
> &outer_for_lifetimes
)
3852 std::vector
<AST::LifetimeParam
> for_lifetimes
= outer_for_lifetimes
;
3854 std::unique_ptr
<AST::Type
> type
= parse_type ();
3855 if (type
== nullptr)
3860 if (!skip_token (COLON
))
3862 // TODO: skip after somewhere
3866 if (lexer
.peek_token ()->get_id () == FOR
)
3868 auto for_lifetimes_inner
= parse_for_lifetimes ();
3869 for_lifetimes
.insert (for_lifetimes
.end (), for_lifetimes_inner
.begin (),
3870 for_lifetimes_inner
.end ());
3873 // parse type param bounds if they exist
3874 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
3875 = parse_type_param_bounds ();
3877 location_t locus
= lexer
.peek_token ()->get_locus ();
3879 return std::unique_ptr
<AST::TypeBoundWhereClauseItem
> (
3880 new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes
),
3882 std::move (type_param_bounds
), locus
));
3885 // Parses a for lifetimes clause, including the for keyword and angle
3887 template <typename ManagedTokenSource
>
3888 std::vector
<AST::LifetimeParam
>
3889 Parser
<ManagedTokenSource
>::parse_for_lifetimes ()
3891 std::vector
<AST::LifetimeParam
> params
;
3893 if (!skip_token (FOR
))
3895 // skip after somewhere?
3899 if (!skip_token (LEFT_ANGLE
))
3901 // skip after somewhere?
3905 /* cannot specify end token due to parsing problems with '>' tokens being
3907 params
= parse_lifetime_params_objs (is_right_angle_tok
);
3909 if (!skip_generics_right_angle ())
3912 rust_debug ("failed to skip generics right angle after (supposedly) "
3913 "finished parsing where clause items");
3914 // ok, well this gets called.
3916 // skip after somewhere?
3923 // Parses type parameter bounds in where clause or generic arguments.
3924 template <typename ManagedTokenSource
>
3925 std::vector
<std::unique_ptr
<AST::TypeParamBound
>>
3926 Parser
<ManagedTokenSource
>::parse_type_param_bounds ()
3928 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
;
3930 std::unique_ptr
<AST::TypeParamBound
> initial_bound
3931 = parse_type_param_bound ();
3933 // quick exit if null
3934 if (initial_bound
== nullptr)
3936 /* error? type param bounds must have at least one term, but are bounds
3938 return type_param_bounds
;
3940 type_param_bounds
.push_back (std::move (initial_bound
));
3942 while (lexer
.peek_token ()->get_id () == PLUS
)
3944 lexer
.skip_token ();
3946 std::unique_ptr
<AST::TypeParamBound
> bound
= parse_type_param_bound ();
3947 if (bound
== nullptr)
3949 /* not an error: bound is allowed to be null as trailing plus is
3951 return type_param_bounds
;
3954 type_param_bounds
.push_back (std::move (bound
));
3957 type_param_bounds
.shrink_to_fit ();
3958 return type_param_bounds
;
3961 /* Parses type parameter bounds in where clause or generic arguments, with end
3962 * token handling. */
3963 template <typename ManagedTokenSource
>
3964 template <typename EndTokenPred
>
3965 std::vector
<std::unique_ptr
<AST::TypeParamBound
>>
3966 Parser
<ManagedTokenSource
>::parse_type_param_bounds (EndTokenPred is_end_token
)
3968 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
;
3970 std::unique_ptr
<AST::TypeParamBound
> initial_bound
3971 = parse_type_param_bound ();
3973 // quick exit if null
3974 if (initial_bound
== nullptr)
3976 /* error? type param bounds must have at least one term, but are bounds
3978 return type_param_bounds
;
3980 type_param_bounds
.push_back (std::move (initial_bound
));
3982 while (lexer
.peek_token ()->get_id () == PLUS
)
3984 lexer
.skip_token ();
3986 // break if end token character
3987 if (is_end_token (lexer
.peek_token ()->get_id ()))
3990 std::unique_ptr
<AST::TypeParamBound
> bound
= parse_type_param_bound ();
3991 if (bound
== nullptr)
3993 // TODO how wise is it to ditch all bounds if only one failed?
3994 Error
error (lexer
.peek_token ()->get_locus (),
3995 "failed to parse type param bound in type param bounds");
3996 add_error (std::move (error
));
4001 type_param_bounds
.push_back (std::move (bound
));
4004 type_param_bounds
.shrink_to_fit ();
4005 return type_param_bounds
;
4008 /* Parses a single type parameter bound in a where clause or generic argument.
4009 * Does not parse the '+' between arguments. */
4010 template <typename ManagedTokenSource
>
4011 std::unique_ptr
<AST::TypeParamBound
>
4012 Parser
<ManagedTokenSource
>::parse_type_param_bound ()
4014 // shitty cheat way of determining lifetime or trait bound - test for
4016 const_TokenPtr t
= lexer
.peek_token ();
4017 switch (t
->get_id ())
4020 return std::unique_ptr
<AST::Lifetime
> (
4021 new AST::Lifetime (parse_lifetime (false).value ()));
4031 case SCOPE_RESOLUTION
:
4032 return parse_trait_bound ();
4034 // don't error - assume this is fine TODO
4039 // Parses a trait bound type param bound.
4040 template <typename ManagedTokenSource
>
4041 std::unique_ptr
<AST::TraitBound
>
4042 Parser
<ManagedTokenSource
>::parse_trait_bound ()
4044 bool has_parens
= false;
4045 bool has_question_mark
= false;
4047 location_t locus
= lexer
.peek_token ()->get_locus ();
4049 /* parse optional `for lifetimes`. */
4050 std::vector
<AST::LifetimeParam
> for_lifetimes
;
4051 if (lexer
.peek_token ()->get_id () == FOR
)
4052 for_lifetimes
= parse_for_lifetimes ();
4054 // handle trait bound being in parentheses
4055 if (lexer
.peek_token ()->get_id () == LEFT_PAREN
)
4058 lexer
.skip_token ();
4061 // handle having question mark (optional)
4062 if (lexer
.peek_token ()->get_id () == QUESTION_MARK
)
4064 has_question_mark
= true;
4065 lexer
.skip_token ();
4069 AST::TypePath type_path
= parse_type_path ();
4071 // handle closing parentheses
4074 if (!skip_token (RIGHT_PAREN
))
4080 return std::unique_ptr
<AST::TraitBound
> (
4081 new AST::TraitBound (std::move (type_path
), locus
, has_parens
,
4082 has_question_mark
, std::move (for_lifetimes
)));
4085 // Parses lifetime bounds.
4086 template <typename ManagedTokenSource
>
4087 std::vector
<AST::Lifetime
>
4088 Parser
<ManagedTokenSource
>::parse_lifetime_bounds ()
4090 std::vector
<AST::Lifetime
> lifetime_bounds
;
4094 auto lifetime
= parse_lifetime (false);
4096 // quick exit for parsing failure
4100 lifetime_bounds
.push_back (std::move (lifetime
.value ()));
4102 /* plus is maybe not allowed at end - spec defines it weirdly, so
4103 * assuming allowed at end */
4104 if (lexer
.peek_token ()->get_id () != PLUS
)
4107 lexer
.skip_token ();
4110 lifetime_bounds
.shrink_to_fit ();
4111 return lifetime_bounds
;
4114 // Parses lifetime bounds, with added check for ending token.
4115 template <typename ManagedTokenSource
>
4116 template <typename EndTokenPred
>
4117 std::vector
<AST::Lifetime
>
4118 Parser
<ManagedTokenSource
>::parse_lifetime_bounds (EndTokenPred is_end_token
)
4120 std::vector
<AST::Lifetime
> lifetime_bounds
;
4122 while (!is_end_token (lexer
.peek_token ()->get_id ()))
4124 auto lifetime
= parse_lifetime (false);
4128 /* TODO: is it worth throwing away all lifetime bound info just
4129 * because one failed? */
4130 Error
error (lexer
.peek_token ()->get_locus (),
4131 "failed to parse lifetime in lifetime bounds");
4132 add_error (std::move (error
));
4137 lifetime_bounds
.push_back (std::move (lifetime
.value ()));
4139 /* plus is maybe not allowed at end - spec defines it weirdly, so
4140 * assuming allowed at end */
4141 if (lexer
.peek_token ()->get_id () != PLUS
)
4144 lexer
.skip_token ();
4147 lifetime_bounds
.shrink_to_fit ();
4148 return lifetime_bounds
;
4151 /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not
4153 template <typename ManagedTokenSource
>
4154 tl::expected
<AST::Lifetime
, ParseLifetimeError
>
4155 Parser
<ManagedTokenSource
>::parse_lifetime (bool allow_elided
)
4157 const_TokenPtr lifetime_tok
= lexer
.peek_token ();
4158 if (lifetime_tok
->get_id () != LIFETIME
)
4162 return AST::Lifetime::elided ();
4166 return tl::make_unexpected
<ParseLifetimeError
> ({});
4169 lexer
.skip_token ();
4171 return lifetime_from_token (lifetime_tok
);
4174 template <typename ManagedTokenSource
>
4176 Parser
<ManagedTokenSource
>::lifetime_from_token (const_TokenPtr tok
)
4178 location_t locus
= tok
->get_locus ();
4179 std::string lifetime_ident
= tok
->get_str ();
4181 if (lifetime_ident
== "static")
4183 return AST::Lifetime (AST::Lifetime::STATIC
, "", locus
);
4185 else if (lifetime_ident
== "_")
4187 // Explicitly and implicitly elided lifetimes follow the same rules.
4188 return AST::Lifetime (AST::Lifetime::WILDCARD
, "", locus
);
4192 return AST::Lifetime (AST::Lifetime::NAMED
, std::move (lifetime_ident
),
4197 template <typename ManagedTokenSource
>
4198 std::unique_ptr
<AST::ExternalTypeItem
>
4199 Parser
<ManagedTokenSource
>::parse_external_type_item (AST::Visibility vis
,
4200 AST::AttrVec outer_attrs
)
4202 location_t locus
= lexer
.peek_token ()->get_locus ();
4205 const_TokenPtr alias_name_tok
= expect_token (IDENTIFIER
);
4206 if (alias_name_tok
== nullptr)
4208 Error
error (lexer
.peek_token ()->get_locus (),
4209 "could not parse identifier in external opaque type");
4210 add_error (std::move (error
));
4212 skip_after_semicolon ();
4216 if (!skip_token (SEMICOLON
))
4219 return std::unique_ptr
<AST::ExternalTypeItem
> (
4220 new AST::ExternalTypeItem (alias_name_tok
->get_str (), std::move (vis
),
4221 std::move (outer_attrs
), std::move (locus
)));
4224 // Parses a "type alias" (typedef) item.
4225 template <typename ManagedTokenSource
>
4226 std::unique_ptr
<AST::TypeAlias
>
4227 Parser
<ManagedTokenSource
>::parse_type_alias (AST::Visibility vis
,
4228 AST::AttrVec outer_attrs
)
4230 location_t locus
= lexer
.peek_token ()->get_locus ();
4233 // TODO: use this token for identifier when finished that
4234 const_TokenPtr alias_name_tok
= expect_token (IDENTIFIER
);
4235 if (alias_name_tok
== nullptr)
4237 Error
error (lexer
.peek_token ()->get_locus (),
4238 "could not parse identifier in type alias");
4239 add_error (std::move (error
));
4241 skip_after_semicolon ();
4244 Identifier alias_name
{alias_name_tok
};
4246 // parse generic params, which may not exist
4247 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
4248 = parse_generic_params_in_angles ();
4250 // parse where clause, which may not exist
4251 AST::WhereClause where_clause
= parse_where_clause ();
4253 if (!skip_token (EQUAL
))
4255 skip_after_semicolon ();
4259 std::unique_ptr
<AST::Type
> type_to_alias
= parse_type ();
4261 if (!skip_token (SEMICOLON
))
4263 // should be skipping past this, not the next line
4267 return std::unique_ptr
<AST::TypeAlias
> (
4268 new AST::TypeAlias (std::move (alias_name
), std::move (generic_params
),
4269 std::move (where_clause
), std::move (type_to_alias
),
4270 std::move (vis
), std::move (outer_attrs
), locus
));
4273 // Parse a struct item AST node.
4274 template <typename ManagedTokenSource
>
4275 std::unique_ptr
<AST::Struct
>
4276 Parser
<ManagedTokenSource
>::parse_struct (AST::Visibility vis
,
4277 AST::AttrVec outer_attrs
)
4279 /* TODO: determine best way to parse the proper struct vs tuple struct -
4280 * share most of initial constructs so lookahead might be impossible, and if
4281 * not probably too expensive. Best way is probably unified parsing for the
4282 * initial parts and then pass them in as params to more derived functions.
4283 * Alternatively, just parse everything in this one function - do this if
4284 * function not too long. */
4286 /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{'
4287 * struct_fields? '}' | ';' ) */
4288 /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')'
4289 * where_clause? ';' */
4290 location_t locus
= lexer
.peek_token ()->get_locus ();
4291 skip_token (STRUCT_KW
);
4293 // parse struct name
4294 const_TokenPtr name_tok
= expect_token (IDENTIFIER
);
4295 if (name_tok
== nullptr)
4297 Error
error (lexer
.peek_token ()->get_locus (),
4298 "could not parse struct or tuple struct identifier");
4299 add_error (std::move (error
));
4301 // skip after somewhere?
4304 Identifier struct_name
{name_tok
};
4306 // parse generic params, which may or may not exist
4307 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
4308 = parse_generic_params_in_angles ();
4310 // branch on next token - determines whether proper struct or tuple struct
4311 if (lexer
.peek_token ()->get_id () == LEFT_PAREN
)
4315 // skip left parenthesis
4316 lexer
.skip_token ();
4318 // parse tuple fields
4319 std::vector
<AST::TupleField
> tuple_fields
;
4320 // Might be empty tuple for unit tuple struct.
4321 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
4322 tuple_fields
= std::vector
<AST::TupleField
> ();
4324 tuple_fields
= parse_tuple_fields ();
4326 // tuple parameters must have closing parenthesis
4327 if (!skip_token (RIGHT_PAREN
))
4329 skip_after_semicolon ();
4333 // parse where clause, which is optional
4334 AST::WhereClause where_clause
= parse_where_clause ();
4336 if (!skip_token (SEMICOLON
))
4338 // can't skip after semicolon because it's meant to be here
4342 return std::unique_ptr
<AST::TupleStruct
> (
4343 new AST::TupleStruct (std::move (tuple_fields
), std::move (struct_name
),
4344 std::move (generic_params
),
4345 std::move (where_clause
), std::move (vis
),
4346 std::move (outer_attrs
), locus
));
4349 // assume it is a proper struct being parsed and continue outside of switch
4350 // - label only here to suppress warning
4352 // parse where clause, which is optional
4353 AST::WhereClause where_clause
= parse_where_clause ();
4355 // branch on next token - determines whether struct is a unit struct
4356 const_TokenPtr t
= lexer
.peek_token ();
4357 switch (t
->get_id ())
4362 // skip curly bracket
4363 lexer
.skip_token ();
4365 // parse struct fields, if any
4366 std::vector
<AST::StructField
> struct_fields
4367 = parse_struct_fields ([] (TokenId id
) { return id
== RIGHT_CURLY
; });
4369 if (!skip_token (RIGHT_CURLY
))
4375 return std::unique_ptr
<AST::StructStruct
> (new AST::StructStruct (
4376 std::move (struct_fields
), std::move (struct_name
),
4377 std::move (generic_params
), std::move (where_clause
), false,
4378 std::move (vis
), std::move (outer_attrs
), locus
));
4381 // unit struct declaration
4383 lexer
.skip_token ();
4385 return std::unique_ptr
<AST::StructStruct
> (
4386 new AST::StructStruct (std::move (struct_name
),
4387 std::move (generic_params
),
4388 std::move (where_clause
), std::move (vis
),
4389 std::move (outer_attrs
), locus
));
4391 add_error (Error (t
->get_locus (),
4392 "unexpected token %qs in struct declaration",
4393 t
->get_token_description ()));
4400 // Parses struct fields in struct declarations.
4401 template <typename ManagedTokenSource
>
4402 std::vector
<AST::StructField
>
4403 Parser
<ManagedTokenSource
>::parse_struct_fields ()
4405 std::vector
<AST::StructField
> fields
;
4407 AST::StructField initial_field
= parse_struct_field ();
4409 // Return empty field list if no field there
4410 if (initial_field
.is_error ())
4413 fields
.push_back (std::move (initial_field
));
4415 while (lexer
.peek_token ()->get_id () == COMMA
)
4417 lexer
.skip_token ();
4419 AST::StructField field
= parse_struct_field ();
4421 if (field
.is_error ())
4423 // would occur with trailing comma, so allowed
4427 fields
.push_back (std::move (field
));
4430 fields
.shrink_to_fit ();
4432 // TODO: template if possible (parse_non_ptr_seq)
4435 // Parses struct fields in struct declarations.
4436 template <typename ManagedTokenSource
>
4437 template <typename EndTokenPred
>
4438 std::vector
<AST::StructField
>
4439 Parser
<ManagedTokenSource
>::parse_struct_fields (EndTokenPred is_end_tok
)
4441 std::vector
<AST::StructField
> fields
;
4443 AST::StructField initial_field
= parse_struct_field ();
4445 // Return empty field list if no field there
4446 if (initial_field
.is_error ())
4449 fields
.push_back (std::move (initial_field
));
4451 while (lexer
.peek_token ()->get_id () == COMMA
)
4453 lexer
.skip_token ();
4455 if (is_end_tok (lexer
.peek_token ()->get_id ()))
4458 AST::StructField field
= parse_struct_field ();
4459 if (field
.is_error ())
4461 /* TODO: should every field be ditched just because one couldn't be
4463 Error
error (lexer
.peek_token ()->get_locus (),
4464 "failed to parse struct field in struct fields");
4465 add_error (std::move (error
));
4470 fields
.push_back (std::move (field
));
4473 fields
.shrink_to_fit ();
4475 // TODO: template if possible (parse_non_ptr_seq)
4478 // Parses a single struct field (in a struct definition). Does not parse
4480 template <typename ManagedTokenSource
>
4482 Parser
<ManagedTokenSource
>::parse_struct_field ()
4484 // parse outer attributes, if they exist
4485 AST::AttrVec outer_attrs
= parse_outer_attributes ();
4487 // parse visibility, if it exists
4488 AST::Visibility vis
= parse_visibility ();
4490 location_t locus
= lexer
.peek_token ()->get_locus ();
4493 const_TokenPtr field_name_tok
= lexer
.peek_token ();
4494 if (field_name_tok
->get_id () != IDENTIFIER
)
4496 // if not identifier, assumes there is no struct field and exits - not
4497 // necessarily error
4498 return AST::StructField::create_error ();
4500 Identifier field_name
{field_name_tok
};
4501 lexer
.skip_token ();
4503 if (!skip_token (COLON
))
4505 // skip after somewhere?
4506 return AST::StructField::create_error ();
4509 // parse field type - this is required
4510 std::unique_ptr
<AST::Type
> field_type
= parse_type ();
4511 if (field_type
== nullptr)
4513 Error
error (lexer
.peek_token ()->get_locus (),
4514 "could not parse type in struct field definition");
4515 add_error (std::move (error
));
4517 // skip after somewhere
4518 return AST::StructField::create_error ();
4521 return AST::StructField (std::move (field_name
), std::move (field_type
),
4522 std::move (vis
), locus
, std::move (outer_attrs
));
4525 // Parses tuple fields in tuple/tuple struct declarations.
4526 template <typename ManagedTokenSource
>
4527 std::vector
<AST::TupleField
>
4528 Parser
<ManagedTokenSource
>::parse_tuple_fields ()
4530 std::vector
<AST::TupleField
> fields
;
4532 AST::TupleField initial_field
= parse_tuple_field ();
4534 // Return empty field list if no field there
4535 if (initial_field
.is_error ())
4540 fields
.push_back (std::move (initial_field
));
4542 // maybe think of a better control structure here - do-while with an initial
4543 // error state? basically, loop through field list until can't find any more
4544 // params HACK: all current syntax uses of tuple fields have them ending
4545 // with a right paren token
4546 const_TokenPtr t
= lexer
.peek_token ();
4547 while (t
->get_id () == COMMA
)
4549 // skip comma if applies - e.g. trailing comma
4550 lexer
.skip_token ();
4552 // break out due to right paren if it exists
4553 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
4558 AST::TupleField field
= parse_tuple_field ();
4559 if (field
.is_error ())
4561 Error
error (lexer
.peek_token ()->get_locus (),
4562 "failed to parse tuple field in tuple fields");
4563 add_error (std::move (error
));
4565 return std::vector
<AST::TupleField
> ();
4568 fields
.push_back (std::move (field
));
4570 t
= lexer
.peek_token ();
4573 fields
.shrink_to_fit ();
4576 // TODO: this shares basically all code with function params and struct
4581 /* Parses a single tuple struct field in a tuple struct definition. Does not
4583 template <typename ManagedTokenSource
>
4585 Parser
<ManagedTokenSource
>::parse_tuple_field ()
4587 // parse outer attributes if they exist
4588 AST::AttrVec outer_attrs
= parse_outer_attributes ();
4590 // parse visibility if it exists
4591 AST::Visibility vis
= parse_visibility ();
4593 location_t locus
= lexer
.peek_token ()->get_locus ();
4595 // parse type, which is required
4596 std::unique_ptr
<AST::Type
> field_type
= parse_type ();
4597 if (field_type
== nullptr)
4600 Error
error (lexer
.peek_token ()->get_locus (),
4601 "could not parse type in tuple struct field");
4602 add_error (std::move (error
));
4604 // skip after something
4605 return AST::TupleField::create_error ();
4608 return AST::TupleField (std::move (field_type
), std::move (vis
), locus
,
4609 std::move (outer_attrs
));
4612 // Parses a Rust "enum" tagged union item definition.
4613 template <typename ManagedTokenSource
>
4614 std::unique_ptr
<AST::Enum
>
4615 Parser
<ManagedTokenSource
>::parse_enum (AST::Visibility vis
,
4616 AST::AttrVec outer_attrs
)
4618 location_t locus
= lexer
.peek_token ()->get_locus ();
4619 skip_token (ENUM_KW
);
4622 const_TokenPtr enum_name_tok
= expect_token (IDENTIFIER
);
4623 if (enum_name_tok
== nullptr)
4626 Identifier enum_name
= {enum_name_tok
};
4628 // parse generic params (of enum container, not enum variants) if they exist
4629 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
4630 = parse_generic_params_in_angles ();
4632 // parse where clause if it exists
4633 AST::WhereClause where_clause
= parse_where_clause ();
4635 if (!skip_token (LEFT_CURLY
))
4637 skip_after_end_block ();
4641 // parse actual enum variant definitions
4642 std::vector
<std::unique_ptr
<AST::EnumItem
>> enum_items
4643 = parse_enum_items ([] (TokenId id
) { return id
== RIGHT_CURLY
; });
4645 if (!skip_token (RIGHT_CURLY
))
4647 skip_after_end_block ();
4651 return std::unique_ptr
<AST::Enum
> (
4652 new AST::Enum (std::move (enum_name
), std::move (vis
),
4653 std::move (generic_params
), std::move (where_clause
),
4654 std::move (enum_items
), std::move (outer_attrs
), locus
));
4657 // Parses the enum variants inside an enum definiton.
4658 template <typename ManagedTokenSource
>
4659 std::vector
<std::unique_ptr
<AST::EnumItem
>>
4660 Parser
<ManagedTokenSource
>::parse_enum_items ()
4662 std::vector
<std::unique_ptr
<AST::EnumItem
>> items
;
4664 std::unique_ptr
<AST::EnumItem
> initial_item
= parse_enum_item ();
4666 // Return empty item list if no field there
4667 if (initial_item
== nullptr)
4670 items
.push_back (std::move (initial_item
));
4672 while (lexer
.peek_token ()->get_id () == COMMA
)
4674 lexer
.skip_token ();
4676 std::unique_ptr
<AST::EnumItem
> item
= parse_enum_item ();
4677 if (item
== nullptr)
4679 // this would occur with a trailing comma, which is allowed
4683 items
.push_back (std::move (item
));
4686 items
.shrink_to_fit ();
4689 /* TODO: use template if doable (parse_non_ptr_sequence) */
4692 // Parses the enum variants inside an enum definiton.
4693 template <typename ManagedTokenSource
>
4694 template <typename EndTokenPred
>
4695 std::vector
<std::unique_ptr
<AST::EnumItem
>>
4696 Parser
<ManagedTokenSource
>::parse_enum_items (EndTokenPred is_end_tok
)
4698 std::vector
<std::unique_ptr
<AST::EnumItem
>> items
;
4700 std::unique_ptr
<AST::EnumItem
> initial_item
= parse_enum_item ();
4702 // Return empty item list if no field there
4703 if (initial_item
== nullptr)
4706 items
.push_back (std::move (initial_item
));
4708 while (lexer
.peek_token ()->get_id () == COMMA
)
4710 lexer
.skip_token ();
4712 if (is_end_tok (lexer
.peek_token ()->get_id ()))
4715 std::unique_ptr
<AST::EnumItem
> item
= parse_enum_item ();
4716 if (item
== nullptr)
4718 /* TODO should this ignore all successfully parsed enum items just
4719 * because one failed? */
4720 Error
error (lexer
.peek_token ()->get_locus (),
4721 "failed to parse enum item in enum items");
4722 add_error (std::move (error
));
4727 items
.push_back (std::move (item
));
4730 items
.shrink_to_fit ();
4733 /* TODO: use template if doable (parse_non_ptr_sequence) */
4736 /* Parses a single enum variant item in an enum definition. Does not parse
4738 template <typename ManagedTokenSource
>
4739 std::unique_ptr
<AST::EnumItem
>
4740 Parser
<ManagedTokenSource
>::parse_enum_item ()
4742 // parse outer attributes if they exist
4743 AST::AttrVec outer_attrs
= parse_outer_attributes ();
4745 // parse visibility, which may or may not exist
4746 AST::Visibility vis
= parse_visibility ();
4748 // parse name for enum item, which is required
4749 const_TokenPtr item_name_tok
= lexer
.peek_token ();
4750 if (item_name_tok
->get_id () != IDENTIFIER
)
4752 // this may not be an error but it means there is no enum item here
4755 lexer
.skip_token ();
4756 Identifier item_name
{item_name_tok
};
4758 // branch based on next token
4759 const_TokenPtr t
= lexer
.peek_token ();
4760 switch (t
->get_id ())
4764 lexer
.skip_token ();
4766 std::vector
<AST::TupleField
> tuple_fields
;
4767 // Might be empty tuple for unit tuple enum variant.
4768 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
4769 tuple_fields
= std::vector
<AST::TupleField
> ();
4771 tuple_fields
= parse_tuple_fields ();
4773 if (!skip_token (RIGHT_PAREN
))
4775 // skip after somewhere
4779 return std::unique_ptr
<AST::EnumItemTuple
> (new AST::EnumItemTuple (
4780 std::move (item_name
), std::move (vis
), std::move (tuple_fields
),
4781 std::move (outer_attrs
), item_name_tok
->get_locus ()));
4785 lexer
.skip_token ();
4787 std::vector
<AST::StructField
> struct_fields
4788 = parse_struct_fields ([] (TokenId id
) { return id
== RIGHT_CURLY
; });
4790 if (!skip_token (RIGHT_CURLY
))
4792 // skip after somewhere
4796 return std::unique_ptr
<AST::EnumItemStruct
> (new AST::EnumItemStruct (
4797 std::move (item_name
), std::move (vis
), std::move (struct_fields
),
4798 std::move (outer_attrs
), item_name_tok
->get_locus ()));
4801 // discriminant enum item
4802 lexer
.skip_token ();
4804 std::unique_ptr
<AST::Expr
> discriminant_expr
= parse_expr ();
4806 return std::unique_ptr
<AST::EnumItemDiscriminant
> (
4807 new AST::EnumItemDiscriminant (std::move (item_name
), std::move (vis
),
4808 std::move (discriminant_expr
),
4809 std::move (outer_attrs
),
4810 item_name_tok
->get_locus ()));
4813 // regular enum with just an identifier
4814 return std::unique_ptr
<AST::EnumItem
> (
4815 new AST::EnumItem (std::move (item_name
), std::move (vis
),
4816 std::move (outer_attrs
),
4817 item_name_tok
->get_locus ()));
4821 // Parses a C-style (and C-compat) untagged union declaration.
4822 template <typename ManagedTokenSource
>
4823 std::unique_ptr
<AST::Union
>
4824 Parser
<ManagedTokenSource
>::parse_union (AST::Visibility vis
,
4825 AST::AttrVec outer_attrs
)
4827 /* hack - "weak keyword" by finding identifier called "union" (lookahead in
4829 const_TokenPtr union_keyword
= expect_token (IDENTIFIER
);
4830 rust_assert (union_keyword
->get_str () == Values::WeakKeywords::UNION
);
4831 location_t locus
= union_keyword
->get_locus ();
4833 // parse actual union name
4834 const_TokenPtr union_name_tok
= expect_token (IDENTIFIER
);
4835 if (union_name_tok
== nullptr)
4837 skip_after_next_block ();
4840 Identifier union_name
{union_name_tok
};
4842 // parse optional generic parameters
4843 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
4844 = parse_generic_params_in_angles ();
4846 // parse optional where clause
4847 AST::WhereClause where_clause
= parse_where_clause ();
4849 if (!skip_token (LEFT_CURLY
))
4851 skip_after_end_block ();
4855 /* parse union inner items as "struct fields" because hey, syntax reuse.
4857 std::vector
<AST::StructField
> union_fields
4858 = parse_struct_fields ([] (TokenId id
) { return id
== RIGHT_CURLY
; });
4860 if (!skip_token (RIGHT_CURLY
))
4862 // skip after somewhere
4866 return std::unique_ptr
<AST::Union
> (
4867 new AST::Union (std::move (union_name
), std::move (vis
),
4868 std::move (generic_params
), std::move (where_clause
),
4869 std::move (union_fields
), std::move (outer_attrs
), locus
));
4872 /* Parses a "constant item" (compile-time constant to maybe "inline"
4873 * throughout the program - like constexpr). */
4874 template <typename ManagedTokenSource
>
4875 std::unique_ptr
<AST::ConstantItem
>
4876 Parser
<ManagedTokenSource
>::parse_const_item (AST::Visibility vis
,
4877 AST::AttrVec outer_attrs
)
4879 location_t locus
= lexer
.peek_token ()->get_locus ();
4882 /* get constant identifier - this is either a proper identifier or the _
4884 const_TokenPtr ident_tok
= lexer
.peek_token ();
4885 // make default identifier the underscore wildcard one
4886 std::string
ident (Values::Keywords::UNDERSCORE
);
4887 switch (ident_tok
->get_id ())
4890 ident
= ident_tok
->get_str ();
4891 lexer
.skip_token ();
4894 // do nothing - identifier is already "_"
4895 lexer
.skip_token ();
4899 Error (ident_tok
->get_locus (),
4900 "expected item name (identifier or %<_%>) in constant item "
4901 "declaration - found %qs",
4902 ident_tok
->get_token_description ()));
4904 skip_after_semicolon ();
4908 if (!skip_token (COLON
))
4910 skip_after_semicolon ();
4914 // parse constant type (required)
4915 std::unique_ptr
<AST::Type
> type
= parse_type ();
4917 // A const with no given expression value
4918 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
4920 lexer
.skip_token ();
4921 return std::unique_ptr
<AST::ConstantItem
> (
4922 new AST::ConstantItem (std::move (ident
), std::move (vis
),
4923 std::move (type
), std::move (outer_attrs
),
4927 if (!skip_token (EQUAL
))
4929 skip_after_semicolon ();
4933 // parse constant expression (required)
4934 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
4936 if (!skip_token (SEMICOLON
))
4942 return std::unique_ptr
<AST::ConstantItem
> (
4943 new AST::ConstantItem (std::move (ident
), std::move (vis
), std::move (type
),
4944 std::move (expr
), std::move (outer_attrs
), locus
));
4947 // Parses a "static item" (static storage item, with 'static lifetime).
4948 template <typename ManagedTokenSource
>
4949 std::unique_ptr
<AST::StaticItem
>
4950 Parser
<ManagedTokenSource
>::parse_static_item (AST::Visibility vis
,
4951 AST::AttrVec outer_attrs
)
4953 location_t locus
= lexer
.peek_token ()->get_locus ();
4954 skip_token (STATIC_KW
);
4956 // determine whether static item is mutable
4957 bool is_mut
= false;
4958 if (lexer
.peek_token ()->get_id () == MUT
)
4961 lexer
.skip_token ();
4964 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
4965 if (ident_tok
== nullptr)
4968 Identifier ident
{ident_tok
};
4970 if (!skip_token (COLON
))
4972 skip_after_semicolon ();
4976 // parse static item type (required)
4977 std::unique_ptr
<AST::Type
> type
= parse_type ();
4979 if (!skip_token (EQUAL
))
4981 skip_after_semicolon ();
4985 // parse static item expression (required)
4986 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
4988 if (!skip_token (SEMICOLON
))
4990 // skip after somewhere
4994 return std::unique_ptr
<AST::StaticItem
> (
4995 new AST::StaticItem (std::move (ident
), is_mut
, std::move (type
),
4996 std::move (expr
), std::move (vis
),
4997 std::move (outer_attrs
), locus
));
5000 // Parses a trait definition item, including unsafe ones.
5001 template <typename ManagedTokenSource
>
5002 std::unique_ptr
<AST::Trait
>
5003 Parser
<ManagedTokenSource
>::parse_trait (AST::Visibility vis
,
5004 AST::AttrVec outer_attrs
)
5006 location_t locus
= lexer
.peek_token ()->get_locus ();
5007 bool is_unsafe
= false;
5008 bool is_auto_trait
= false;
5010 if (lexer
.peek_token ()->get_id () == UNSAFE
)
5013 lexer
.skip_token ();
5016 if (lexer
.peek_token ()->get_id () == AUTO
)
5018 is_auto_trait
= true;
5019 lexer
.skip_token ();
5025 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
5026 if (ident_tok
== nullptr)
5029 Identifier ident
{ident_tok
};
5031 // parse generic parameters (if they exist)
5032 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
5033 = parse_generic_params_in_angles ();
5035 // create placeholder type param bounds in case they don't exist
5036 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
;
5038 // parse type param bounds (if they exist)
5039 if (lexer
.peek_token ()->get_id () == COLON
)
5041 lexer
.skip_token ();
5043 type_param_bounds
= parse_type_param_bounds (
5044 [] (TokenId id
) { return id
== WHERE
|| id
== LEFT_CURLY
; });
5045 // type_param_bounds = parse_type_param_bounds ();
5048 // parse where clause (if it exists)
5049 AST::WhereClause where_clause
= parse_where_clause ();
5051 if (!skip_token (LEFT_CURLY
))
5053 skip_after_end_block ();
5057 // parse inner attrs (if they exist)
5058 AST::AttrVec inner_attrs
= parse_inner_attributes ();
5060 // parse trait items
5061 std::vector
<std::unique_ptr
<AST::AssociatedItem
>> trait_items
;
5063 const_TokenPtr t
= lexer
.peek_token ();
5064 while (t
->get_id () != RIGHT_CURLY
)
5066 std::unique_ptr
<AST::AssociatedItem
> trait_item
= parse_trait_item ();
5068 if (trait_item
== nullptr)
5070 Error
error (lexer
.peek_token ()->get_locus (),
5071 "failed to parse trait item in trait");
5072 add_error (std::move (error
));
5076 trait_items
.push_back (std::move (trait_item
));
5078 t
= lexer
.peek_token ();
5081 if (!skip_token (RIGHT_CURLY
))
5083 // skip after something
5087 trait_items
.shrink_to_fit ();
5088 return std::unique_ptr
<AST::Trait
> (
5089 new AST::Trait (std::move (ident
), is_unsafe
, is_auto_trait
,
5090 std::move (generic_params
), std::move (type_param_bounds
),
5091 std::move (where_clause
), std::move (trait_items
),
5092 std::move (vis
), std::move (outer_attrs
),
5093 std::move (inner_attrs
), locus
));
5096 // Parses a trait item used inside traits (not trait, the Item).
5097 template <typename ManagedTokenSource
>
5098 std::unique_ptr
<AST::AssociatedItem
>
5099 Parser
<ManagedTokenSource
>::parse_trait_item ()
5101 // parse outer attributes (if they exist)
5102 AST::AttrVec outer_attrs
= parse_outer_attributes ();
5104 AST::Visibility vis
= parse_visibility ();
5106 // lookahead to determine what type of trait item to parse
5107 const_TokenPtr tok
= lexer
.peek_token ();
5108 switch (tok
->get_id ())
5114 // these seem to be SimplePath tokens, so this is a macro invocation
5116 return parse_macro_invocation_semi (std::move (outer_attrs
));
5118 if (lexer
.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT
)
5119 return parse_function (std::move (vis
), std::move (outer_attrs
));
5121 return parse_macro_invocation_semi (std::move (outer_attrs
));
5123 return parse_trait_type (std::move (outer_attrs
), vis
);
5125 // disambiguate with function qualifier
5126 if (lexer
.peek_token (1)->get_id () == IDENTIFIER
)
5128 return parse_trait_const (std::move (outer_attrs
));
5130 // else, fallthrough to function
5131 // TODO: find out how to disable gcc "implicit fallthrough" error
5137 return parse_function (std::move (vis
), std::move (outer_attrs
));
5141 add_error (Error (tok
->get_locus (),
5142 "unrecognised token %qs for item in trait",
5143 tok
->get_token_description ()));
5148 // Parse a typedef trait item.
5149 template <typename ManagedTokenSource
>
5150 std::unique_ptr
<AST::TraitItemType
>
5151 Parser
<ManagedTokenSource
>::parse_trait_type (AST::AttrVec outer_attrs
,
5152 AST::Visibility vis
)
5154 location_t locus
= lexer
.peek_token ()->get_locus ();
5157 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
5158 if (ident_tok
== nullptr)
5161 Identifier ident
{ident_tok
};
5163 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
5165 // parse optional colon
5166 if (lexer
.peek_token ()->get_id () == COLON
)
5168 lexer
.skip_token ();
5170 // parse optional type param bounds
5172 = parse_type_param_bounds ([] (TokenId id
) { return id
== SEMICOLON
; });
5173 // bounds = parse_type_param_bounds ();
5176 if (!skip_token (SEMICOLON
))
5182 return std::unique_ptr
<AST::TraitItemType
> (
5183 new AST::TraitItemType (std::move (ident
), std::move (bounds
),
5184 std::move (outer_attrs
), vis
, locus
));
5187 // Parses a constant trait item.
5188 template <typename ManagedTokenSource
>
5189 std::unique_ptr
<AST::TraitItemConst
>
5190 Parser
<ManagedTokenSource
>::parse_trait_const (AST::AttrVec outer_attrs
)
5192 location_t locus
= lexer
.peek_token ()->get_locus ();
5195 // parse constant item name
5196 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
5197 if (ident_tok
== nullptr)
5200 Identifier ident
{ident_tok
};
5202 if (!skip_token (COLON
))
5204 skip_after_semicolon ();
5208 // parse constant trait item type
5209 std::unique_ptr
<AST::Type
> type
= parse_type ();
5211 // parse constant trait body expression, if it exists
5212 std::unique_ptr
<AST::Expr
> const_body
= nullptr;
5213 if (lexer
.peek_token ()->get_id () == EQUAL
)
5215 lexer
.skip_token ();
5217 // expression must exist, so parse it
5218 const_body
= parse_expr ();
5221 if (!skip_token (SEMICOLON
))
5223 // skip after something?
5227 return std::unique_ptr
<AST::TraitItemConst
> (
5228 new AST::TraitItemConst (std::move (ident
), std::move (type
),
5229 std::move (const_body
), std::move (outer_attrs
),
5233 /* Parses a struct "impl" item (both inherent impl and trait impl can be
5235 template <typename ManagedTokenSource
>
5236 std::unique_ptr
<AST::Impl
>
5237 Parser
<ManagedTokenSource
>::parse_impl (AST::Visibility vis
,
5238 AST::AttrVec outer_attrs
)
5240 /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
5241 * must be a trait impl. However, this isn't enough for full disambiguation,
5242 * so don't branch here. */
5243 location_t locus
= lexer
.peek_token ()->get_locus ();
5244 bool is_unsafe
= false;
5245 if (lexer
.peek_token ()->get_id () == UNSAFE
)
5247 lexer
.skip_token ();
5251 if (!skip_token (IMPL
))
5253 skip_after_next_block ();
5257 // parse generic params (shared by trait and inherent impls)
5258 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
5259 = parse_generic_params_in_angles ();
5261 // Again, trait impl-only feature, but optional one, so can be used for
5263 bool has_exclam
= false;
5264 if (lexer
.peek_token ()->get_id () == EXCLAM
)
5266 lexer
.skip_token ();
5270 /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
5271 * doesn't parse too much and not work. */
5272 AST::TypePath type_path
= parse_type_path ();
5273 if (type_path
.is_error () || lexer
.peek_token ()->get_id () != FOR
)
5275 /* cannot parse type path (or not for token next, at least), so must be
5278 // hacky conversion of TypePath stack object to Type pointer
5279 std::unique_ptr
<AST::Type
> type
= nullptr;
5280 if (!type_path
.is_error ())
5281 type
= std::unique_ptr
<AST::TypePath
> (
5282 new AST::TypePath (std::move (type_path
)));
5284 type
= parse_type ();
5286 // Type is required, so error if null
5287 if (type
== nullptr)
5289 Error
error (lexer
.peek_token ()->get_locus (),
5290 "could not parse type in inherent impl");
5291 add_error (std::move (error
));
5293 skip_after_next_block ();
5297 // parse optional where clause
5298 AST::WhereClause where_clause
= parse_where_clause ();
5300 if (!skip_token (LEFT_CURLY
))
5302 // TODO: does this still skip properly?
5303 skip_after_end_block ();
5307 // parse inner attributes (optional)
5308 AST::AttrVec inner_attrs
= parse_inner_attributes ();
5310 // parse inherent impl items
5311 std::vector
<std::unique_ptr
<AST::AssociatedItem
>> impl_items
;
5313 const_TokenPtr t
= lexer
.peek_token ();
5314 while (t
->get_id () != RIGHT_CURLY
)
5316 std::unique_ptr
<AST::AssociatedItem
> impl_item
5317 = parse_inherent_impl_item ();
5319 if (impl_item
== nullptr)
5322 lexer
.peek_token ()->get_locus (),
5323 "failed to parse inherent impl item in inherent impl");
5324 add_error (std::move (error
));
5329 impl_items
.push_back (std::move (impl_item
));
5331 t
= lexer
.peek_token ();
5334 if (!skip_token (RIGHT_CURLY
))
5341 rust_debug ("successfully parsed inherent impl");
5343 impl_items
.shrink_to_fit ();
5345 return std::unique_ptr
<AST::InherentImpl
> (new AST::InherentImpl (
5346 std::move (impl_items
), std::move (generic_params
), std::move (type
),
5347 std::move (where_clause
), std::move (vis
), std::move (inner_attrs
),
5348 std::move (outer_attrs
), locus
));
5352 // type path must both be valid and next token is for, so trait impl
5353 if (!skip_token (FOR
))
5355 skip_after_next_block ();
5360 std::unique_ptr
<AST::Type
> type
= parse_type ();
5361 // ensure type is included as it is required
5362 if (type
== nullptr)
5364 Error
error (lexer
.peek_token ()->get_locus (),
5365 "could not parse type in trait impl");
5366 add_error (std::move (error
));
5368 skip_after_next_block ();
5372 // parse optional where clause
5373 AST::WhereClause where_clause
= parse_where_clause ();
5375 if (!skip_token (LEFT_CURLY
))
5377 // TODO: does this still skip properly?
5378 skip_after_end_block ();
5382 // parse inner attributes (optional)
5383 AST::AttrVec inner_attrs
= parse_inner_attributes ();
5385 // parse trait impl items
5386 std::vector
<std::unique_ptr
<AST::AssociatedItem
>> impl_items
;
5388 const_TokenPtr t
= lexer
.peek_token ();
5389 while (t
->get_id () != RIGHT_CURLY
)
5391 std::unique_ptr
<AST::AssociatedItem
> impl_item
5392 = parse_trait_impl_item ();
5394 if (impl_item
== nullptr)
5396 Error
error (lexer
.peek_token ()->get_locus (),
5397 "failed to parse trait impl item in trait impl");
5398 add_error (std::move (error
));
5403 impl_items
.push_back (std::move (impl_item
));
5405 t
= lexer
.peek_token ();
5408 rust_debug ("successfully parsed a trait impl item");
5411 rust_debug ("successfully finished trait impl items");
5413 if (!skip_token (RIGHT_CURLY
))
5420 rust_debug ("successfully parsed trait impl");
5422 impl_items
.shrink_to_fit ();
5424 return std::unique_ptr
<AST::TraitImpl
> (
5425 new AST::TraitImpl (std::move (type_path
), is_unsafe
, has_exclam
,
5426 std::move (impl_items
), std::move (generic_params
),
5427 std::move (type
), std::move (where_clause
),
5428 std::move (vis
), std::move (inner_attrs
),
5429 std::move (outer_attrs
), locus
));
5433 // Parses a single inherent impl item (item inside an inherent impl block).
5434 template <typename ManagedTokenSource
>
5435 std::unique_ptr
<AST::AssociatedItem
>
5436 Parser
<ManagedTokenSource
>::parse_inherent_impl_item ()
5438 // parse outer attributes (if they exist)
5439 AST::AttrVec outer_attrs
= parse_outer_attributes ();
5441 // TODO: cleanup - currently an unreadable mess
5443 // branch on next token:
5444 const_TokenPtr t
= lexer
.peek_token ();
5445 switch (t
->get_id ())
5448 // FIXME: Arthur: Do we need to some lookahead here?
5449 return parse_macro_invocation_semi (outer_attrs
);
5454 // visibility, so not a macro invocation semi - must be constant,
5455 // function, or method
5456 AST::Visibility vis
= parse_visibility ();
5458 // TODO: is a recursive call to parse_inherent_impl_item better?
5459 switch (lexer
.peek_token ()->get_id ())
5464 // function or method
5465 return parse_inherent_impl_function_or_method (std::move (vis
),
5469 // lookahead to resolve production - could be function/method or
5471 t
= lexer
.peek_token (1);
5473 switch (t
->get_id ())
5477 return parse_const_item (std::move (vis
),
5478 std::move (outer_attrs
));
5482 return parse_inherent_impl_function_or_method (std::move (vis
),
5486 add_error (Error (t
->get_locus (),
5487 "unexpected token %qs in some sort of const "
5488 "item in inherent impl",
5489 t
->get_token_description ()));
5491 lexer
.skip_token (1); // TODO: is this right thing to do?
5496 Error (t
->get_locus (),
5497 "unrecognised token %qs for item in inherent impl",
5498 t
->get_token_description ()));
5507 // function or method
5508 return parse_inherent_impl_function_or_method (
5509 AST::Visibility::create_private (), std::move (outer_attrs
));
5511 /* lookahead to resolve production - could be function/method or const
5513 t
= lexer
.peek_token (1);
5515 switch (t
->get_id ())
5519 return parse_const_item (AST::Visibility::create_private (),
5520 std::move (outer_attrs
));
5524 return parse_inherent_impl_function_or_method (
5525 AST::Visibility::create_private (), std::move (outer_attrs
));
5527 add_error (Error (t
->get_locus (),
5528 "unexpected token %qs in some sort of const item "
5530 t
->get_token_description ()));
5532 lexer
.skip_token (1); // TODO: is this right thing to do?
5535 rust_unreachable ();
5537 add_error (Error (t
->get_locus (),
5538 "unrecognised token %qs for item in inherent impl",
5539 t
->get_token_description ()));
5546 /* For internal use only by parse_inherent_impl_item() - splits giant method
5547 * into smaller ones and prevents duplication of logic. Strictly, this parses
5548 * a function or method item inside an inherent impl item block. */
5549 // TODO: make this a templated function with "return type" as type param -
5550 // InherentImplItem is this specialisation of the template while TraitImplItem
5551 // will be the other.
5552 template <typename ManagedTokenSource
>
5553 std::unique_ptr
<AST::AssociatedItem
>
5554 Parser
<ManagedTokenSource
>::parse_inherent_impl_function_or_method (
5555 AST::Visibility vis
, AST::AttrVec outer_attrs
)
5557 location_t locus
= lexer
.peek_token ()->get_locus ();
5558 // parse function or method qualifiers
5559 AST::FunctionQualifiers qualifiers
= parse_function_qualifiers ();
5563 // parse function or method name
5564 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
5565 if (ident_tok
== nullptr)
5568 Identifier ident
{ident_tok
};
5570 // parse generic params
5571 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
5572 = parse_generic_params_in_angles ();
5574 if (!skip_token (LEFT_PAREN
))
5576 // skip after somewhere?
5580 // now for function vs method disambiguation - method has opening "self"
5582 auto initial_param
= parse_self_param ();
5584 if (!initial_param
.has_value () && initial_param
.error () != NOT_SELF
)
5587 /* FIXME: ensure that self param doesn't accidently consume tokens for a
5588 * function one idea is to lookahead up to 4 tokens to see whether self is
5590 bool is_method
= false;
5591 if (initial_param
.has_value ())
5593 if ((*initial_param
)->is_self ())
5596 /* skip comma so function and method regular params can be parsed in
5598 if (lexer
.peek_token ()->get_id () == COMMA
)
5599 lexer
.skip_token ();
5602 // parse trait function params
5603 std::vector
<std::unique_ptr
<AST::Param
>> function_params
5604 = parse_function_params ([] (TokenId id
) { return id
== RIGHT_PAREN
; });
5606 if (initial_param
.has_value ())
5607 function_params
.insert (function_params
.begin (),
5608 std::move (*initial_param
));
5610 if (!skip_token (RIGHT_PAREN
))
5612 skip_after_end_block ();
5616 // parse return type (optional)
5617 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
5619 // parse where clause (optional)
5620 AST::WhereClause where_clause
= parse_where_clause ();
5622 tl::optional
<std::unique_ptr
<AST::BlockExpr
>> body
= tl::nullopt
;
5623 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
5624 lexer
.skip_token ();
5627 auto result
= parse_block_expr ();
5629 if (result
== nullptr)
5632 lexer
.peek_token ()->get_locus (),
5633 "could not parse definition in inherent impl %s definition",
5634 is_method
? "method" : "function");
5635 add_error (std::move (error
));
5637 skip_after_end_block ();
5640 body
= std::move (result
);
5643 return std::unique_ptr
<AST::Function
> (
5644 new AST::Function (std::move (ident
), std::move (qualifiers
),
5645 std::move (generic_params
), std::move (function_params
),
5646 std::move (return_type
), std::move (where_clause
),
5647 std::move (body
), std::move (vis
),
5648 std::move (outer_attrs
), locus
));
5651 // Parses a single trait impl item (item inside a trait impl block).
5652 template <typename ManagedTokenSource
>
5653 std::unique_ptr
<AST::AssociatedItem
>
5654 Parser
<ManagedTokenSource
>::parse_trait_impl_item ()
5656 // parse outer attributes (if they exist)
5657 AST::AttrVec outer_attrs
= parse_outer_attributes ();
5659 auto visibility
= AST::Visibility::create_private ();
5660 if (lexer
.peek_token ()->get_id () == PUB
)
5661 visibility
= parse_visibility ();
5663 // branch on next token:
5664 const_TokenPtr t
= lexer
.peek_token ();
5665 switch (t
->get_id ())
5671 // these seem to be SimplePath tokens, so this is a macro invocation
5673 return parse_macro_invocation_semi (std::move (outer_attrs
));
5675 if (lexer
.peek_token ()->get_str () == Values::WeakKeywords::DEFAULT
)
5676 return parse_trait_impl_function_or_method (visibility
,
5677 std::move (outer_attrs
));
5679 return parse_macro_invocation_semi (std::move (outer_attrs
));
5681 return parse_type_alias (visibility
, std::move (outer_attrs
));
5685 // function or method
5686 return parse_trait_impl_function_or_method (visibility
,
5687 std::move (outer_attrs
));
5689 return parse_async_item (visibility
, std::move (outer_attrs
));
5691 // lookahead to resolve production - could be function/method or const
5693 t
= lexer
.peek_token (1);
5695 switch (t
->get_id ())
5699 return parse_const_item (visibility
, std::move (outer_attrs
));
5703 return parse_trait_impl_function_or_method (visibility
,
5704 std::move (outer_attrs
));
5708 "unexpected token %qs in some sort of const item in trait impl",
5709 t
->get_token_description ()));
5711 lexer
.skip_token (1); // TODO: is this right thing to do?
5714 rust_unreachable ();
5718 add_error (Error (t
->get_locus (),
5719 "unrecognised token %qs for item in trait impl",
5720 t
->get_token_description ()));
5726 /* For internal use only by parse_trait_impl_item() - splits giant method into
5727 * smaller ones and prevents duplication of logic. Strictly, this parses a
5728 * function or method item inside a trait impl item block. */
5729 template <typename ManagedTokenSource
>
5730 std::unique_ptr
<AST::AssociatedItem
>
5731 Parser
<ManagedTokenSource
>::parse_trait_impl_function_or_method (
5732 AST::Visibility vis
, AST::AttrVec outer_attrs
)
5734 // this shares virtually all logic with
5735 // parse_inherent_impl_function_or_method
5737 location_t locus
= lexer
.peek_token ()->get_locus ();
5739 auto is_default
= false;
5740 auto t
= lexer
.peek_token ();
5741 if (t
->get_id () == IDENTIFIER
5742 && t
->get_str () == Values::WeakKeywords::DEFAULT
)
5745 lexer
.skip_token ();
5748 // parse function or method qualifiers
5749 AST::FunctionQualifiers qualifiers
= parse_function_qualifiers ();
5753 // parse function or method name
5754 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
5755 if (ident_tok
== nullptr)
5759 Identifier ident
{ident_tok
};
5763 "about to start parsing generic params in trait impl function or method");
5765 // parse generic params
5766 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
5767 = parse_generic_params_in_angles ();
5771 "finished parsing generic params in trait impl function or method");
5773 if (!skip_token (LEFT_PAREN
))
5775 // skip after somewhere?
5779 // now for function vs method disambiguation - method has opening "self"
5781 auto initial_param
= parse_self_param ();
5783 if (!initial_param
.has_value () && initial_param
.error () != NOT_SELF
)
5786 // FIXME: ensure that self param doesn't accidently consume tokens for a
5788 bool is_method
= false;
5789 if (initial_param
.has_value ())
5791 if ((*initial_param
)->is_self ())
5794 // skip comma so function and method regular params can be parsed in
5796 if (lexer
.peek_token ()->get_id () == COMMA
)
5798 lexer
.skip_token ();
5802 rust_debug ("successfully parsed self param in method trait impl item");
5807 "started to parse function params in function or method trait impl item");
5809 // parse trait function params (only if next token isn't right paren)
5810 std::vector
<std::unique_ptr
<AST::Param
>> function_params
;
5811 if (lexer
.peek_token ()->get_id () != RIGHT_PAREN
)
5814 = parse_function_params ([] (TokenId id
) { return id
== RIGHT_PAREN
; });
5816 if (function_params
.empty ())
5819 lexer
.peek_token ()->get_locus (),
5820 "failed to parse function params in trait impl %s definition",
5821 is_method
? "method" : "function");
5822 add_error (std::move (error
));
5824 skip_after_next_block ();
5829 if (initial_param
.has_value ())
5830 function_params
.insert (function_params
.begin (),
5831 std::move (*initial_param
));
5834 rust_debug ("successfully parsed function params in function or method "
5837 if (!skip_token (RIGHT_PAREN
))
5839 skip_after_next_block ();
5843 // parse return type (optional)
5844 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
5848 "successfully parsed return type in function or method trait impl item");
5850 // parse where clause (optional)
5851 AST::WhereClause where_clause
= parse_where_clause ();
5855 "successfully parsed where clause in function or method trait impl item");
5857 // parse function definition (in block) - semicolon not allowed
5858 tl::optional
<std::unique_ptr
<AST::BlockExpr
>> body
= tl::nullopt
;
5860 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
5861 lexer
.skip_token ();
5864 auto result
= parse_block_expr ();
5865 if (result
== nullptr)
5867 Error
error (lexer
.peek_token ()->get_locus (),
5868 "could not parse definition in trait impl %s definition",
5869 is_method
? "method" : "function");
5870 add_error (std::move (error
));
5872 skip_after_end_block ();
5875 body
= std::move (result
);
5878 return std::unique_ptr
<AST::Function
> (
5879 new AST::Function (std::move (ident
), std::move (qualifiers
),
5880 std::move (generic_params
), std::move (function_params
),
5881 std::move (return_type
), std::move (where_clause
),
5882 std::move (body
), std::move (vis
),
5883 std::move (outer_attrs
), locus
, is_default
));
5886 // Parses an extern block of declarations.
5887 template <typename ManagedTokenSource
>
5888 std::unique_ptr
<AST::ExternBlock
>
5889 Parser
<ManagedTokenSource
>::parse_extern_block (AST::Visibility vis
,
5890 AST::AttrVec outer_attrs
)
5892 location_t locus
= lexer
.peek_token ()->get_locus ();
5893 skip_token (EXTERN_KW
);
5895 // detect optional abi name
5897 const_TokenPtr next_tok
= lexer
.peek_token ();
5898 if (next_tok
->get_id () == STRING_LITERAL
)
5900 lexer
.skip_token ();
5901 abi
= next_tok
->get_str ();
5904 if (!skip_token (LEFT_CURLY
))
5906 skip_after_end_block ();
5910 AST::AttrVec inner_attrs
= parse_inner_attributes ();
5912 // parse declarations inside extern block
5913 std::vector
<std::unique_ptr
<AST::ExternalItem
>> extern_items
;
5915 const_TokenPtr t
= lexer
.peek_token ();
5916 while (t
->get_id () != RIGHT_CURLY
)
5918 std::unique_ptr
<AST::ExternalItem
> extern_item
= parse_external_item ();
5920 if (extern_item
== nullptr)
5922 Error
error (t
->get_locus (),
5923 "failed to parse external item despite not reaching "
5924 "end of extern block");
5925 add_error (std::move (error
));
5930 extern_items
.push_back (std::move (extern_item
));
5932 t
= lexer
.peek_token ();
5935 if (!skip_token (RIGHT_CURLY
))
5941 extern_items
.shrink_to_fit ();
5943 return std::unique_ptr
<AST::ExternBlock
> (
5944 new AST::ExternBlock (std::move (abi
), std::move (extern_items
),
5945 std::move (vis
), std::move (inner_attrs
),
5946 std::move (outer_attrs
), locus
));
5949 // Parses a single extern block item (static or function declaration).
5950 template <typename ManagedTokenSource
>
5951 std::unique_ptr
<AST::ExternalItem
>
5952 Parser
<ManagedTokenSource
>::parse_external_item ()
5954 // parse optional outer attributes
5955 AST::AttrVec outer_attrs
= parse_outer_attributes ();
5957 location_t locus
= lexer
.peek_token ()->get_locus ();
5959 // parse optional visibility
5960 AST::Visibility vis
= parse_visibility ();
5962 const_TokenPtr t
= lexer
.peek_token ();
5963 switch (t
->get_id ())
5966 return parse_macro_invocation_semi (outer_attrs
);
5968 // parse extern static item
5969 lexer
.skip_token ();
5971 // parse mut (optional)
5972 bool has_mut
= false;
5973 if (lexer
.peek_token ()->get_id () == MUT
)
5975 lexer
.skip_token ();
5980 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
5981 if (ident_tok
== nullptr)
5983 skip_after_semicolon ();
5986 Identifier ident
{ident_tok
};
5988 if (!skip_token (COLON
))
5990 skip_after_semicolon ();
5994 // parse type (required)
5995 std::unique_ptr
<AST::Type
> type
= parse_type ();
5996 if (type
== nullptr)
5998 Error
error (lexer
.peek_token ()->get_locus (),
5999 "failed to parse type in external static item");
6000 add_error (std::move (error
));
6002 skip_after_semicolon ();
6006 if (!skip_token (SEMICOLON
))
6008 // skip after somewhere?
6012 return std::unique_ptr
<AST::ExternalStaticItem
> (
6013 new AST::ExternalStaticItem (std::move (ident
), std::move (type
),
6014 has_mut
, std::move (vis
),
6015 std::move (outer_attrs
), locus
));
6018 return parse_function (std::move (vis
), std::move (outer_attrs
), true);
6021 return parse_external_type_item (std::move (vis
),
6022 std::move (outer_attrs
));
6026 Error (t
->get_locus (),
6027 "unrecognised token %qs in extern block item declaration",
6028 t
->get_token_description ()));
6030 skip_after_semicolon ();
6035 // Parses a statement (will further disambiguate any statement).
6036 template <typename ManagedTokenSource
>
6037 std::unique_ptr
<AST::Stmt
>
6038 Parser
<ManagedTokenSource
>::parse_stmt (ParseRestrictions restrictions
)
6040 // quick exit for empty statement
6041 // FIXME: Can we have empty statements without semicolons? Just nothing?
6042 const_TokenPtr t
= lexer
.peek_token ();
6043 if (t
->get_id () == SEMICOLON
)
6045 lexer
.skip_token ();
6046 return std::unique_ptr
<AST::EmptyStmt
> (
6047 new AST::EmptyStmt (t
->get_locus ()));
6050 // parse outer attributes
6051 AST::AttrVec outer_attrs
= parse_outer_attributes ();
6053 // parsing this will be annoying because of the many different possibilities
6054 /* best may be just to copy paste in parse_item switch, and failing that try
6055 * to parse outer attributes, and then pass them in to either a let
6056 * statement or (fallback) expression statement. */
6057 // FIXME: think of a way to do this without such a large switch?
6058 t
= lexer
.peek_token ();
6059 switch (t
->get_id ())
6063 return parse_let_stmt (std::move (outer_attrs
), restrictions
);
6078 /* TODO: implement union keyword but not really because of
6079 * context-dependence crappy hack way to parse a union written below to
6080 * separate it from the good code. */
6082 case UNSAFE
: // maybe - unsafe traits are a thing
6083 /* if any of these (should be all possible VisItem prefixes), parse a
6084 * VisItem can't parse item because would require reparsing outer
6086 // may also be unsafe block
6087 if (lexer
.peek_token (1)->get_id () == LEFT_CURLY
)
6089 return parse_expr_stmt (std::move (outer_attrs
), restrictions
);
6093 return parse_vis_item (std::move (outer_attrs
));
6096 // crappy hack to do union "keyword"
6098 if (t
->get_str () == Values::WeakKeywords::UNION
6099 && lexer
.peek_token (1)->get_id () == IDENTIFIER
)
6101 return parse_vis_item (std::move (outer_attrs
));
6102 // or should this go straight to parsing union?
6104 else if (is_macro_rules_def (t
))
6106 // macro_rules! macro item
6107 return parse_macro_rules_def (std::move (outer_attrs
));
6110 // TODO: find out how to disable gcc "implicit fallthrough" warning
6112 // fallback: expression statement
6113 return parse_expr_stmt (std::move (outer_attrs
), restrictions
);
6118 // Parses a let statement.
6119 template <typename ManagedTokenSource
>
6120 std::unique_ptr
<AST::LetStmt
>
6121 Parser
<ManagedTokenSource
>::parse_let_stmt (AST::AttrVec outer_attrs
,
6122 ParseRestrictions restrictions
)
6124 location_t locus
= lexer
.peek_token ()->get_locus ();
6127 // parse pattern (required)
6128 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
6129 if (pattern
== nullptr)
6131 Error
error (lexer
.peek_token ()->get_locus (),
6132 "failed to parse pattern in let statement");
6133 add_error (std::move (error
));
6135 skip_after_semicolon ();
6139 // parse type declaration (optional)
6140 std::unique_ptr
<AST::Type
> type
= nullptr;
6141 if (lexer
.peek_token ()->get_id () == COLON
)
6143 // must have a type declaration
6144 lexer
.skip_token ();
6146 type
= parse_type ();
6147 if (type
== nullptr)
6149 Error
error (lexer
.peek_token ()->get_locus (),
6150 "failed to parse type in let statement");
6151 add_error (std::move (error
));
6153 skip_after_semicolon ();
6158 // parse expression to set variable to (optional)
6159 std::unique_ptr
<AST::Expr
> expr
= nullptr;
6160 if (lexer
.peek_token ()->get_id () == EQUAL
)
6162 // must have an expression
6163 lexer
.skip_token ();
6165 expr
= parse_expr ();
6166 if (expr
== nullptr)
6168 Error
error (lexer
.peek_token ()->get_locus (),
6169 "failed to parse expression in let statement");
6170 add_error (std::move (error
));
6172 skip_after_semicolon ();
6177 tl::optional
<std::unique_ptr
<AST::Expr
>> else_expr
= tl::nullopt
;
6178 if (maybe_skip_token (ELSE
))
6179 else_expr
= parse_block_expr ();
6181 if (restrictions
.consume_semi
)
6183 // `stmt` macro variables are parsed without a semicolon, but should be
6184 // parsed as a full statement when interpolated. This should be handled
6185 // by having the interpolated statement be distinguishable from normal
6186 // tokens, e.g. by NT tokens.
6187 if (restrictions
.allow_close_after_expr_stmt
)
6188 maybe_skip_token (SEMICOLON
);
6189 else if (!skip_token (SEMICOLON
))
6193 return std::unique_ptr
<AST::LetStmt
> (
6194 new AST::LetStmt (std::move (pattern
), std::move (expr
), std::move (type
),
6195 std::move (else_expr
), std::move (outer_attrs
), locus
));
6198 // Parses a type path.
6199 template <typename ManagedTokenSource
>
6201 Parser
<ManagedTokenSource
>::parse_type_path ()
6203 bool has_opening_scope_resolution
= false;
6204 location_t locus
= lexer
.peek_token ()->get_locus ();
6205 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
)
6207 has_opening_scope_resolution
= true;
6208 lexer
.skip_token ();
6211 // create segment vector
6212 std::vector
<std::unique_ptr
<AST::TypePathSegment
>> segments
;
6214 // parse required initial segment
6215 std::unique_ptr
<AST::TypePathSegment
> initial_segment
6216 = parse_type_path_segment ();
6217 if (initial_segment
== nullptr)
6219 // skip after somewhere?
6220 // don't necessarily throw error but yeah
6221 return AST::TypePath::create_error ();
6223 segments
.push_back (std::move (initial_segment
));
6225 // parse optional segments (as long as scope resolution operator exists)
6226 const_TokenPtr t
= lexer
.peek_token ();
6227 while (t
->get_id () == SCOPE_RESOLUTION
)
6229 // skip scope resolution operator
6230 lexer
.skip_token ();
6232 // parse the actual segment - it is an error if it doesn't exist now
6233 std::unique_ptr
<AST::TypePathSegment
> segment
6234 = parse_type_path_segment ();
6235 if (segment
== nullptr)
6237 // skip after somewhere?
6238 Error
error (t
->get_locus (), "could not parse type path segment");
6239 add_error (std::move (error
));
6241 return AST::TypePath::create_error ();
6244 segments
.push_back (std::move (segment
));
6246 t
= lexer
.peek_token ();
6249 segments
.shrink_to_fit ();
6251 return AST::TypePath (std::move (segments
), locus
,
6252 has_opening_scope_resolution
);
6255 template <typename ManagedTokenSource
>
6256 tl::optional
<AST::GenericArg
>
6257 Parser
<ManagedTokenSource
>::parse_generic_arg ()
6259 auto tok
= lexer
.peek_token ();
6260 std::unique_ptr
<AST::Expr
> expr
= nullptr;
6262 switch (tok
->get_id ())
6265 // This is a bit of a weird situation: With an identifier token, we
6266 // could either have a valid type or a macro (FIXME: anything else?). So
6267 // we need one bit of lookahead to differentiate if this is really
6268 auto next_tok
= lexer
.peek_token (1);
6269 if (next_tok
->get_id () == LEFT_ANGLE
6270 || next_tok
->get_id () == SCOPE_RESOLUTION
6271 || next_tok
->get_id () == EXCLAM
)
6273 auto type
= parse_type ();
6275 return AST::GenericArg::create_type (std::move (type
));
6279 else if (next_tok
->get_id () == COLON
)
6281 lexer
.skip_token (); // skip ident
6282 lexer
.skip_token (); // skip colon
6284 auto tok
= lexer
.peek_token ();
6285 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
6286 = parse_type_param_bounds ();
6288 auto type
= std::unique_ptr
<AST::TraitObjectType
> (
6289 new AST::TraitObjectType (std::move (bounds
), tok
->get_locus (),
6292 return AST::GenericArg::create_type (std::move (type
));
6296 lexer
.skip_token ();
6297 return AST::GenericArg::create_ambiguous (tok
->get_str (),
6301 expr
= parse_block_expr ();
6304 case STRING_LITERAL
:
6310 expr
= parse_literal_expr ();
6312 // FIXME: Because of this, error reporting is garbage for const generic
6313 // parameter's default values
6315 auto type
= parse_type ();
6316 // FIXME: Find a better way to do this?
6318 return AST::GenericArg::create_type (std::move (type
));
6327 return AST::GenericArg::create_const (std::move (expr
));
6330 // Parses the generic arguments in each path segment.
6331 template <typename ManagedTokenSource
>
6333 Parser
<ManagedTokenSource
>::parse_path_generic_args ()
6335 if (lexer
.peek_token ()->get_id () == LEFT_SHIFT
)
6336 lexer
.split_current_token (LEFT_ANGLE
, LEFT_ANGLE
);
6338 if (!skip_token (LEFT_ANGLE
))
6340 // skip after somewhere?
6341 return AST::GenericArgs::create_empty ();
6344 // We need to parse all lifetimes, then parse types and const generics in
6347 // try to parse lifetimes first
6348 std::vector
<AST::Lifetime
> lifetime_args
;
6350 const_TokenPtr t
= lexer
.peek_token ();
6351 location_t locus
= t
->get_locus ();
6352 while (!is_right_angle_tok (t
->get_id ()))
6354 auto lifetime
= parse_lifetime (false);
6357 // not necessarily an error
6361 lifetime_args
.push_back (std::move (lifetime
.value ()));
6363 // if next token isn't comma, then it must be end of list
6364 if (lexer
.peek_token ()->get_id () != COMMA
)
6369 lexer
.skip_token ();
6371 t
= lexer
.peek_token ();
6374 // try to parse types and const generics second
6375 std::vector
<AST::GenericArg
> generic_args
;
6377 // TODO: think of better control structure
6378 t
= lexer
.peek_token ();
6379 while (!is_right_angle_tok (t
->get_id ()))
6381 // FIXME: Is it fine to break if there is one binding? Can't there be
6382 // bindings in between types?
6384 // ensure not binding being parsed as type accidently
6385 if (t
->get_id () == IDENTIFIER
6386 && lexer
.peek_token (1)->get_id () == EQUAL
)
6389 auto arg
= parse_generic_arg ();
6392 generic_args
.emplace_back (std::move (arg
.value ()));
6395 // FIXME: Do we need to break if we encounter an error?
6397 // if next token isn't comma, then it must be end of list
6398 if (lexer
.peek_token ()->get_id () != COMMA
)
6402 lexer
.skip_token ();
6403 t
= lexer
.peek_token ();
6406 // try to parse bindings third
6407 std::vector
<AST::GenericArgsBinding
> binding_args
;
6409 // TODO: think of better control structure
6410 t
= lexer
.peek_token ();
6411 while (!is_right_angle_tok (t
->get_id ()))
6413 AST::GenericArgsBinding binding
= parse_generic_args_binding ();
6414 if (binding
.is_error ())
6416 // not necessarily an error
6420 binding_args
.push_back (std::move (binding
));
6422 // if next token isn't comma, then it must be end of list
6423 if (lexer
.peek_token ()->get_id () != COMMA
)
6428 lexer
.skip_token ();
6430 t
= lexer
.peek_token ();
6433 // skip any trailing commas
6434 if (lexer
.peek_token ()->get_id () == COMMA
)
6435 lexer
.skip_token ();
6437 if (!skip_generics_right_angle ())
6438 return AST::GenericArgs::create_empty ();
6440 lifetime_args
.shrink_to_fit ();
6441 generic_args
.shrink_to_fit ();
6442 binding_args
.shrink_to_fit ();
6444 return AST::GenericArgs (std::move (lifetime_args
), std::move (generic_args
),
6445 std::move (binding_args
), locus
);
6448 // Parses a binding in a generic args path segment.
6449 template <typename ManagedTokenSource
>
6450 AST::GenericArgsBinding
6451 Parser
<ManagedTokenSource
>::parse_generic_args_binding ()
6453 const_TokenPtr ident_tok
= lexer
.peek_token ();
6454 if (ident_tok
->get_id () != IDENTIFIER
)
6456 // allow non error-inducing use
6458 return AST::GenericArgsBinding::create_error ();
6460 lexer
.skip_token ();
6461 Identifier ident
{ident_tok
};
6463 if (!skip_token (EQUAL
))
6465 // skip after somewhere?
6466 return AST::GenericArgsBinding::create_error ();
6469 // parse type (required)
6470 std::unique_ptr
<AST::Type
> type
= parse_type ();
6471 if (type
== nullptr)
6474 return AST::GenericArgsBinding::create_error ();
6477 return AST::GenericArgsBinding (std::move (ident
), std::move (type
),
6478 ident_tok
->get_locus ());
6481 /* Parses a single type path segment (not including opening scope resolution,
6482 * but includes any internal ones). Includes generic args or type path
6484 template <typename ManagedTokenSource
>
6485 std::unique_ptr
<AST::TypePathSegment
>
6486 Parser
<ManagedTokenSource
>::parse_type_path_segment ()
6488 location_t locus
= lexer
.peek_token ()->get_locus ();
6489 // parse ident segment part
6490 AST::PathIdentSegment ident_segment
= parse_path_ident_segment ();
6491 if (ident_segment
.is_error ())
6493 // not necessarily an error
6497 /* lookahead to determine if variants exist - only consume scope resolution
6499 bool has_separating_scope_resolution
= false;
6500 const_TokenPtr next
= lexer
.peek_token (1);
6501 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
6502 && (next
->get_id () == LEFT_ANGLE
|| next
->get_id () == LEFT_PAREN
))
6504 has_separating_scope_resolution
= true;
6505 lexer
.skip_token ();
6508 // branch into variants on next token
6509 const_TokenPtr t
= lexer
.peek_token ();
6510 switch (t
->get_id ())
6514 // parse generic args
6515 AST::GenericArgs generic_args
= parse_path_generic_args ();
6517 return std::unique_ptr
<AST::TypePathSegmentGeneric
> (
6518 new AST::TypePathSegmentGeneric (std::move (ident_segment
),
6519 has_separating_scope_resolution
,
6520 std::move (generic_args
), locus
));
6523 // parse type path function
6524 AST::TypePathFunction type_path_function
6525 = parse_type_path_function (locus
);
6527 if (type_path_function
.is_error ())
6529 // skip after somewhere?
6533 return std::unique_ptr
<AST::TypePathSegmentFunction
> (
6534 new AST::TypePathSegmentFunction (std::move (ident_segment
),
6535 has_separating_scope_resolution
,
6536 std::move (type_path_function
),
6541 return std::unique_ptr
<AST::TypePathSegment
> (
6542 new AST::TypePathSegment (std::move (ident_segment
),
6543 has_separating_scope_resolution
, locus
));
6545 rust_unreachable ();
6548 // Parses a function call representation inside a type path.
6549 template <typename ManagedTokenSource
>
6550 AST::TypePathFunction
6551 Parser
<ManagedTokenSource
>::parse_type_path_function (location_t id_location
)
6553 if (!skip_token (LEFT_PAREN
))
6556 return AST::TypePathFunction::create_error ();
6559 // parse function inputs
6560 std::vector
<std::unique_ptr
<AST::Type
>> inputs
;
6562 while (lexer
.peek_token ()->get_id () != RIGHT_PAREN
)
6564 std::unique_ptr
<AST::Type
> type
= parse_type ();
6565 if (type
== nullptr)
6567 /* this is an error as there should've been a ')' there if there
6570 lexer
.peek_token ()->get_locus (),
6571 "failed to parse type in parameters of type path function");
6572 add_error (std::move (error
));
6575 return AST::TypePathFunction::create_error ();
6578 inputs
.push_back (std::move (type
));
6580 // skip commas, including trailing commas
6581 if (lexer
.peek_token ()->get_id () != COMMA
)
6584 lexer
.skip_token ();
6587 if (!skip_token (RIGHT_PAREN
))
6590 return AST::TypePathFunction::create_error ();
6593 // parse optional return type
6594 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
6596 inputs
.shrink_to_fit ();
6597 return AST::TypePathFunction (std::move (inputs
), id_location
,
6598 std::move (return_type
));
6601 // Parses a path inside an expression that allows generic arguments.
6602 template <typename ManagedTokenSource
>
6603 AST::PathInExpression
6604 Parser
<ManagedTokenSource
>::parse_path_in_expression ()
6606 location_t locus
= UNKNOWN_LOCATION
;
6607 bool has_opening_scope_resolution
= false;
6608 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
)
6610 has_opening_scope_resolution
= true;
6612 locus
= lexer
.peek_token ()->get_locus ();
6614 lexer
.skip_token ();
6617 // create segment vector
6618 std::vector
<AST::PathExprSegment
> segments
;
6620 if (locus
== UNKNOWN_LOCATION
)
6622 locus
= lexer
.peek_token ()->get_locus ();
6625 // parse required initial segment
6626 AST::PathExprSegment initial_segment
= parse_path_expr_segment ();
6627 if (initial_segment
.is_error ())
6629 // skip after somewhere?
6630 // don't necessarily throw error but yeah
6631 return AST::PathInExpression::create_error ();
6633 segments
.push_back (std::move (initial_segment
));
6635 // parse optional segments (as long as scope resolution operator exists)
6636 const_TokenPtr t
= lexer
.peek_token ();
6637 while (t
->get_id () == SCOPE_RESOLUTION
)
6639 // skip scope resolution operator
6640 lexer
.skip_token ();
6642 // parse the actual segment - it is an error if it doesn't exist now
6643 AST::PathExprSegment segment
= parse_path_expr_segment ();
6644 if (segment
.is_error ())
6646 // skip after somewhere?
6647 Error
error (t
->get_locus (),
6648 "could not parse path expression segment");
6649 add_error (std::move (error
));
6651 return AST::PathInExpression::create_error ();
6654 segments
.push_back (std::move (segment
));
6656 t
= lexer
.peek_token ();
6659 segments
.shrink_to_fit ();
6661 return AST::PathInExpression (std::move (segments
), {}, locus
,
6662 has_opening_scope_resolution
);
6665 /* Parses a single path in expression path segment (including generic
6667 template <typename ManagedTokenSource
>
6668 AST::PathExprSegment
6669 Parser
<ManagedTokenSource
>::parse_path_expr_segment ()
6671 location_t locus
= lexer
.peek_token ()->get_locus ();
6672 // parse ident segment
6673 AST::PathIdentSegment ident
= parse_path_ident_segment ();
6674 if (ident
.is_error ())
6676 // not necessarily an error?
6677 return AST::PathExprSegment::create_error ();
6680 // parse generic args (and turbofish), if they exist
6681 /* use lookahead to determine if they actually exist (don't want to
6682 * accidently parse over next ident segment) */
6683 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
6684 && (lexer
.peek_token (1)->get_id () == LEFT_ANGLE
6685 || lexer
.peek_token (1)->get_id () == LEFT_SHIFT
))
6687 // skip scope resolution
6688 lexer
.skip_token ();
6690 // Let parse_path_generic_args split "<<" tokens
6691 AST::GenericArgs generic_args
= parse_path_generic_args ();
6693 return AST::PathExprSegment (std::move (ident
), locus
,
6694 std::move (generic_args
));
6697 // return a generic parameter-less expr segment if not found
6698 return AST::PathExprSegment (std::move (ident
), locus
);
6701 /* Parses a fully qualified path in expression (i.e. a pattern). FIXME does
6702 * not parse outer attrs. */
6703 template <typename ManagedTokenSource
>
6704 AST::QualifiedPathInExpression
6705 Parser
<ManagedTokenSource
>::parse_qualified_path_in_expression (
6706 location_t pratt_parsed_loc
)
6708 /* Note: the Rust grammar is defined in such a way that it is impossible to
6709 * determine whether a prospective qualified path is a
6710 * QualifiedPathInExpression or QualifiedPathInType in all cases by the
6711 * rules themselves (the only possible difference is a TypePathSegment with
6712 * function, and lookahead to find this is too difficult). However, as this
6713 * is a pattern and QualifiedPathInType is a type, I believe it that their
6714 * construction will not be confused (due to rules regarding patterns vs
6716 * As such, this function will not attempt to minimise errors created by
6717 * their confusion. */
6719 // parse the qualified path type (required)
6720 AST::QualifiedPathType qual_path_type
6721 = parse_qualified_path_type (pratt_parsed_loc
);
6722 if (qual_path_type
.is_error ())
6724 // TODO: should this create a parse error?
6725 return AST::QualifiedPathInExpression::create_error ();
6727 location_t locus
= qual_path_type
.get_locus ();
6729 // parse path segments
6730 std::vector
<AST::PathExprSegment
> segments
;
6732 // parse initial required segment
6733 if (!expect_token (SCOPE_RESOLUTION
))
6735 // skip after somewhere?
6737 return AST::QualifiedPathInExpression::create_error ();
6739 AST::PathExprSegment initial_segment
= parse_path_expr_segment ();
6740 if (initial_segment
.is_error ())
6742 // skip after somewhere?
6743 Error
error (lexer
.peek_token ()->get_locus (),
6744 "required initial path expression segment in "
6745 "qualified path in expression could not be parsed");
6746 add_error (std::move (error
));
6748 return AST::QualifiedPathInExpression::create_error ();
6750 segments
.push_back (std::move (initial_segment
));
6752 // parse optional segments (as long as scope resolution operator exists)
6753 const_TokenPtr t
= lexer
.peek_token ();
6754 while (t
->get_id () == SCOPE_RESOLUTION
)
6756 // skip scope resolution operator
6757 lexer
.skip_token ();
6759 // parse the actual segment - it is an error if it doesn't exist now
6760 AST::PathExprSegment segment
= parse_path_expr_segment ();
6761 if (segment
.is_error ())
6763 // skip after somewhere?
6764 Error
error (t
->get_locus (),
6765 "could not parse path expression segment in qualified "
6766 "path in expression");
6767 add_error (std::move (error
));
6769 return AST::QualifiedPathInExpression::create_error ();
6772 segments
.push_back (std::move (segment
));
6774 t
= lexer
.peek_token ();
6777 segments
.shrink_to_fit ();
6779 // FIXME: outer attr parsing
6780 return AST::QualifiedPathInExpression (std::move (qual_path_type
),
6781 std::move (segments
), {}, locus
);
6784 // Parses the type syntactical construction at the start of a qualified path.
6785 template <typename ManagedTokenSource
>
6786 AST::QualifiedPathType
6787 Parser
<ManagedTokenSource
>::parse_qualified_path_type (
6788 location_t pratt_parsed_loc
)
6790 location_t locus
= pratt_parsed_loc
;
6791 /* TODO: should this actually be error? is there anywhere where this could
6793 if (locus
== UNKNOWN_LOCATION
)
6795 locus
= lexer
.peek_token ()->get_locus ();
6797 if (lexer
.peek_token ()->get_id () == LEFT_SHIFT
)
6798 lexer
.split_current_token (LEFT_ANGLE
, LEFT_ANGLE
);
6800 // skip after somewhere?
6801 if (!skip_token (LEFT_ANGLE
))
6802 return AST::QualifiedPathType::create_error ();
6805 // parse type (required)
6806 std::unique_ptr
<AST::Type
> type
= parse_type ();
6807 if (type
== nullptr)
6809 Error
error (lexer
.peek_token ()->get_locus (),
6810 "could not parse type in qualified path type");
6811 add_error (std::move (error
));
6814 return AST::QualifiedPathType::create_error ();
6817 // parse optional as clause
6818 AST::TypePath as_type_path
= AST::TypePath::create_error ();
6819 if (lexer
.peek_token ()->get_id () == AS
)
6821 lexer
.skip_token ();
6823 // parse type path, which is required now
6824 as_type_path
= parse_type_path ();
6825 if (as_type_path
.is_error ())
6828 lexer
.peek_token ()->get_locus (),
6829 "could not parse type path in as clause in qualified path type");
6830 add_error (std::move (error
));
6833 return AST::QualifiedPathType::create_error ();
6837 /* NOTE: should actually be a right-angle token, so
6838 * skip_generics_right_angle shouldn't be required */
6839 if (!skip_token (RIGHT_ANGLE
))
6841 // skip after somewhere?
6842 return AST::QualifiedPathType::create_error ();
6845 return AST::QualifiedPathType (std::move (type
), locus
,
6846 std::move (as_type_path
));
6849 // Parses a fully qualified path in type (i.e. a type).
6850 template <typename ManagedTokenSource
>
6851 AST::QualifiedPathInType
6852 Parser
<ManagedTokenSource
>::parse_qualified_path_in_type ()
6854 location_t locus
= lexer
.peek_token ()->get_locus ();
6855 // parse the qualified path type (required)
6856 AST::QualifiedPathType qual_path_type
= parse_qualified_path_type ();
6857 if (qual_path_type
.is_error ())
6859 // TODO: should this create a parse error?
6860 return AST::QualifiedPathInType::create_error ();
6863 // parse initial required segment
6864 if (!expect_token (SCOPE_RESOLUTION
))
6866 // skip after somewhere?
6868 return AST::QualifiedPathInType::create_error ();
6870 std::unique_ptr
<AST::TypePathSegment
> initial_segment
6871 = parse_type_path_segment ();
6872 if (initial_segment
== nullptr)
6874 // skip after somewhere?
6875 Error
error (lexer
.peek_token ()->get_locus (),
6876 "required initial type path segment in qualified path in "
6877 "type could not be parsed");
6878 add_error (std::move (error
));
6880 return AST::QualifiedPathInType::create_error ();
6883 // parse optional segments (as long as scope resolution operator exists)
6884 std::vector
<std::unique_ptr
<AST::TypePathSegment
>> segments
;
6885 const_TokenPtr t
= lexer
.peek_token ();
6886 while (t
->get_id () == SCOPE_RESOLUTION
)
6888 // skip scope resolution operator
6889 lexer
.skip_token ();
6891 // parse the actual segment - it is an error if it doesn't exist now
6892 std::unique_ptr
<AST::TypePathSegment
> segment
6893 = parse_type_path_segment ();
6894 if (segment
== nullptr)
6896 // skip after somewhere?
6899 "could not parse type path segment in qualified path in type");
6900 add_error (std::move (error
));
6902 return AST::QualifiedPathInType::create_error ();
6905 segments
.push_back (std::move (segment
));
6907 t
= lexer
.peek_token ();
6910 segments
.shrink_to_fit ();
6912 return AST::QualifiedPathInType (std::move (qual_path_type
),
6913 std::move (initial_segment
),
6914 std::move (segments
), locus
);
6917 // Parses a self param. Also handles self param not existing.
6918 template <typename ManagedTokenSource
>
6919 tl::expected
<std::unique_ptr
<AST::Param
>, ParseSelfError
>
6920 Parser
<ManagedTokenSource
>::parse_self_param ()
6922 bool has_reference
= false;
6923 AST::Lifetime lifetime
= AST::Lifetime::elided ();
6925 location_t locus
= lexer
.peek_token ()->get_locus ();
6927 // TODO: Feels off, find a better way to clearly express this
6928 std::vector
<std::vector
<TokenId
>> ptrs
6929 = {{ASTERISK
, SELF
} /* *self */,
6930 {ASTERISK
, CONST
, SELF
} /* *const self */,
6931 {ASTERISK
, MUT
, SELF
} /* *mut self */};
6933 for (auto &s
: ptrs
)
6936 for (i
= 0; i
< s
.size (); i
++)
6937 if (lexer
.peek_token (i
)->get_id () != s
[i
])
6941 rust_error_at (lexer
.peek_token ()->get_locus (),
6942 "cannot pass %<self%> by raw pointer");
6943 return tl::make_unexpected (ParseSelfError::SELF_PTR
);
6947 // Trying to find those patterns:
6949 // &'lifetime mut self
6956 // If not found, it is probably a function, exit and let function parsing
6958 bool is_self
= false;
6959 for (size_t i
= 0; i
< 5; i
++)
6960 if (lexer
.peek_token (i
)->get_id () == SELF
)
6964 return tl::make_unexpected (ParseSelfError::NOT_SELF
);
6966 // test if self is a reference parameter
6967 if (lexer
.peek_token ()->get_id () == AMP
)
6969 has_reference
= true;
6970 lexer
.skip_token ();
6972 // now test whether it has a lifetime
6973 if (lexer
.peek_token ()->get_id () == LIFETIME
)
6975 // something went wrong somehow
6976 if (auto parsed_lifetime
= parse_lifetime (true))
6978 lifetime
= parsed_lifetime
.value ();
6982 Error
error (lexer
.peek_token ()->get_locus (),
6983 "failed to parse lifetime in self param");
6984 add_error (std::move (error
));
6986 // skip after somewhere?
6987 return tl::make_unexpected (ParseSelfError::PARSING
);
6993 bool has_mut
= false;
6994 if (lexer
.peek_token ()->get_id () == MUT
)
6997 lexer
.skip_token ();
7001 const_TokenPtr self_tok
= lexer
.peek_token ();
7002 if (self_tok
->get_id () != SELF
)
7004 // skip after somewhere?
7005 return tl::make_unexpected (ParseSelfError::NOT_SELF
);
7007 lexer
.skip_token ();
7009 // parse optional type
7010 std::unique_ptr
<AST::Type
> type
= nullptr;
7011 if (lexer
.peek_token ()->get_id () == COLON
)
7013 lexer
.skip_token ();
7015 // type is now required
7016 type
= parse_type ();
7017 if (type
== nullptr)
7019 Error
error (lexer
.peek_token ()->get_locus (),
7020 "could not parse type in self param");
7021 add_error (std::move (error
));
7023 // skip after somewhere?
7024 return tl::make_unexpected (ParseSelfError::PARSING
);
7028 // ensure that cannot have both type and reference
7029 if (type
!= nullptr && has_reference
)
7032 lexer
.peek_token ()->get_locus (),
7033 "cannot have both a reference and a type specified in a self param");
7034 add_error (std::move (error
));
7036 // skip after somewhere?
7037 return tl::make_unexpected (ParseSelfError::PARSING
);
7042 return std::make_unique
<AST::SelfParam
> (std::move (lifetime
), has_mut
,
7047 // note that type may be nullptr here and that's fine
7048 return std::make_unique
<AST::SelfParam
> (std::move (type
), has_mut
,
7053 /* Parses an expression or macro statement. */
7054 template <typename ManagedTokenSource
>
7055 std::unique_ptr
<AST::Stmt
>
7056 Parser
<ManagedTokenSource
>::parse_expr_stmt (AST::AttrVec outer_attrs
,
7057 ParseRestrictions restrictions
)
7059 location_t locus
= lexer
.peek_token ()->get_locus ();
7061 std::unique_ptr
<AST::Expr
> expr
;
7063 switch (lexer
.peek_token ()->get_id ())
7071 case SCOPE_RESOLUTION
: {
7072 AST::PathInExpression path
= parse_path_in_expression ();
7073 std::unique_ptr
<AST::Expr
> null_denotation
;
7075 if (lexer
.peek_token ()->get_id () == EXCLAM
)
7077 // Bind a reference to avoid -Wredundant-move on post-P1825R0
7078 // compilers. Change to non-reference type and remove the moves
7079 // below once C++20 is required to build gcc.
7080 std::unique_ptr
<AST::MacroInvocation
> &&invoc
7081 = parse_macro_invocation_partial (std::move (path
),
7082 std::move (outer_attrs
));
7084 if (restrictions
.consume_semi
&& maybe_skip_token (SEMICOLON
))
7086 invoc
->add_semicolon ();
7087 // Macro invocation with semicolon.
7088 return std::move (invoc
);
7091 TokenId after_macro
= lexer
.peek_token ()->get_id ();
7093 if (restrictions
.allow_close_after_expr_stmt
7094 && (after_macro
== RIGHT_PAREN
|| after_macro
== RIGHT_CURLY
7095 || after_macro
== RIGHT_SQUARE
))
7096 return std::move (invoc
);
7098 if (invoc
->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
7100 && after_macro
!= DOT
&& after_macro
!= QUESTION_MARK
)
7102 rust_debug ("braced macro statement");
7103 return std::move (invoc
);
7106 null_denotation
= std::move (invoc
);
7111 = null_denotation_path (std::move (path
), {}, restrictions
);
7114 expr
= left_denotations (std::move (null_denotation
), LBP_LOWEST
,
7115 std::move (outer_attrs
), restrictions
);
7119 restrictions
.expr_can_be_stmt
= true;
7120 expr
= parse_expr (std::move (outer_attrs
), restrictions
);
7124 if (expr
== nullptr)
7126 // expr is required, error
7127 Error
error (lexer
.peek_token ()->get_locus (),
7128 "failed to parse expr in expr statement");
7129 add_error (std::move (error
));
7131 skip_after_semicolon ();
7135 bool has_semi
= false;
7137 if (restrictions
.consume_semi
)
7139 if (maybe_skip_token (SEMICOLON
))
7143 else if (expr
->is_expr_without_block ())
7145 if (restrictions
.allow_close_after_expr_stmt
)
7147 TokenId id
= lexer
.peek_token ()->get_id ();
7148 if (id
!= RIGHT_PAREN
&& id
!= RIGHT_CURLY
&& id
!= RIGHT_SQUARE
)
7150 expect_token (SEMICOLON
);
7156 expect_token (SEMICOLON
);
7162 return std::unique_ptr
<AST::ExprStmt
> (
7163 new AST::ExprStmt (std::move (expr
), locus
, has_semi
));
7166 // Parses a block expression, including the curly braces at start and end.
7167 template <typename ManagedTokenSource
>
7168 std::unique_ptr
<AST::BlockExpr
>
7169 Parser
<ManagedTokenSource
>::parse_block_expr (
7170 AST::AttrVec outer_attrs
, tl::optional
<AST::LoopLabel
> label
,
7171 location_t pratt_parsed_loc
)
7173 location_t locus
= pratt_parsed_loc
;
7174 if (locus
== UNKNOWN_LOCATION
)
7176 locus
= lexer
.peek_token ()->get_locus ();
7177 if (!skip_token (LEFT_CURLY
))
7179 skip_after_end_block ();
7184 AST::AttrVec inner_attrs
= parse_inner_attributes ();
7186 // parse statements and expression
7187 std::vector
<std::unique_ptr
<AST::Stmt
>> stmts
;
7188 std::unique_ptr
<AST::Expr
> expr
= nullptr;
7190 const_TokenPtr t
= lexer
.peek_token ();
7191 while (t
->get_id () != RIGHT_CURLY
)
7193 ExprOrStmt expr_or_stmt
= parse_stmt_or_expr ();
7194 if (expr_or_stmt
.is_error ())
7198 "failed to parse statement or expression in block expression");
7199 add_error (std::move (error
));
7204 t
= lexer
.peek_token ();
7206 if (expr_or_stmt
.stmt
!= nullptr)
7208 stmts
.push_back (std::move (expr_or_stmt
.stmt
));
7212 // assign to expression and end parsing inside
7213 expr
= std::move (expr_or_stmt
.expr
);
7218 location_t end_locus
= t
->get_locus ();
7220 if (!skip_token (RIGHT_CURLY
))
7222 Error
error (t
->get_locus (),
7223 "error may be from having an expression (as opposed to "
7224 "statement) in the body of the function but not last");
7225 add_error (std::move (error
));
7227 skip_after_end_block ();
7231 // grammar allows for empty block expressions
7233 stmts
.shrink_to_fit ();
7235 return std::unique_ptr
<AST::BlockExpr
> (
7236 new AST::BlockExpr (std::move (stmts
), std::move (expr
),
7237 std::move (inner_attrs
), std::move (outer_attrs
),
7238 std::move (label
), locus
, end_locus
));
7241 /* Parses a "grouped" expression (expression in parentheses), used to control
7243 template <typename ManagedTokenSource
>
7244 std::unique_ptr
<AST::GroupedExpr
>
7245 Parser
<ManagedTokenSource
>::parse_grouped_expr (AST::AttrVec outer_attrs
)
7247 location_t locus
= lexer
.peek_token ()->get_locus ();
7248 skip_token (LEFT_PAREN
);
7250 AST::AttrVec inner_attrs
= parse_inner_attributes ();
7252 // parse required expr inside parentheses
7253 std::unique_ptr
<AST::Expr
> expr_in_parens
= parse_expr ();
7254 if (expr_in_parens
== nullptr)
7256 // skip after somewhere?
7261 if (!skip_token (RIGHT_PAREN
))
7263 // skip after somewhere?
7267 return std::unique_ptr
<AST::GroupedExpr
> (
7268 new AST::GroupedExpr (std::move (expr_in_parens
), std::move (inner_attrs
),
7269 std::move (outer_attrs
), locus
));
7272 // Parses a closure expression (closure definition).
7273 template <typename ManagedTokenSource
>
7274 std::unique_ptr
<AST::ClosureExpr
>
7275 Parser
<ManagedTokenSource
>::parse_closure_expr (AST::AttrVec outer_attrs
)
7277 location_t locus
= lexer
.peek_token ()->get_locus ();
7278 // detect optional "move"
7279 bool has_move
= false;
7280 if (lexer
.peek_token ()->get_id () == MOVE
)
7282 lexer
.skip_token ();
7286 // handle parameter list
7287 std::vector
<AST::ClosureParam
> params
;
7289 const_TokenPtr t
= lexer
.peek_token ();
7290 switch (t
->get_id ())
7293 // skip token, no parameters
7294 lexer
.skip_token ();
7297 // actually may have parameters
7298 lexer
.skip_token ();
7299 t
= lexer
.peek_token ();
7301 while (t
->get_id () != PIPE
)
7303 AST::ClosureParam param
= parse_closure_param ();
7304 if (param
.is_error ())
7306 // TODO is this really an error?
7307 Error
error (t
->get_locus (), "could not parse closure param");
7308 add_error (std::move (error
));
7312 params
.push_back (std::move (param
));
7314 if (lexer
.peek_token ()->get_id () != COMMA
)
7316 lexer
.skip_token ();
7317 // not an error but means param list is done
7321 lexer
.skip_token ();
7323 t
= lexer
.peek_token ();
7325 params
.shrink_to_fit ();
7328 add_error (Error (t
->get_locus (),
7329 "unexpected token %qs in closure expression - expected "
7331 t
->get_token_description ()));
7337 // again branch based on next token
7338 t
= lexer
.peek_token ();
7339 if (t
->get_id () == RETURN_TYPE
)
7341 // must be return type closure with block expr
7343 // skip "return type" token
7344 lexer
.skip_token ();
7346 // parse actual type, which is required
7347 std::unique_ptr
<AST::TypeNoBounds
> type
= parse_type_no_bounds ();
7348 if (type
== nullptr)
7351 Error
error (t
->get_locus (), "failed to parse type for closure");
7352 add_error (std::move (error
));
7358 // parse block expr, which is required
7359 std::unique_ptr
<AST::BlockExpr
> block
= parse_block_expr ();
7360 if (block
== nullptr)
7363 Error
error (lexer
.peek_token ()->get_locus (),
7364 "failed to parse block expr in closure");
7365 add_error (std::move (error
));
7371 return std::unique_ptr
<AST::ClosureExprInnerTyped
> (
7372 new AST::ClosureExprInnerTyped (std::move (type
), std::move (block
),
7373 std::move (params
), locus
, has_move
,
7374 std::move (outer_attrs
)));
7378 // must be expr-only closure
7380 // parse expr, which is required
7381 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
7382 if (expr
== nullptr)
7384 Error
error (t
->get_locus (),
7385 "failed to parse expression in closure");
7386 add_error (std::move (error
));
7392 return std::unique_ptr
<AST::ClosureExprInner
> (
7393 new AST::ClosureExprInner (std::move (expr
), std::move (params
), locus
,
7394 has_move
, std::move (outer_attrs
)));
7398 // Parses a literal token (to literal expression).
7399 template <typename ManagedTokenSource
>
7400 std::unique_ptr
<AST::LiteralExpr
>
7401 Parser
<ManagedTokenSource
>::parse_literal_expr (AST::AttrVec outer_attrs
)
7403 // TODO: change if literal representation in lexer changes
7405 std::string literal_value
;
7406 AST::Literal::LitType type
= AST::Literal::STRING
;
7408 // branch based on token
7409 const_TokenPtr t
= lexer
.peek_token ();
7410 switch (t
->get_id ())
7413 type
= AST::Literal::CHAR
;
7414 literal_value
= t
->get_str ();
7415 lexer
.skip_token ();
7417 case STRING_LITERAL
:
7418 type
= AST::Literal::STRING
;
7419 literal_value
= t
->get_str ();
7420 lexer
.skip_token ();
7422 case BYTE_CHAR_LITERAL
:
7423 type
= AST::Literal::BYTE
;
7424 literal_value
= t
->get_str ();
7425 lexer
.skip_token ();
7427 case BYTE_STRING_LITERAL
:
7428 type
= AST::Literal::BYTE_STRING
;
7429 literal_value
= t
->get_str ();
7430 lexer
.skip_token ();
7432 case RAW_STRING_LITERAL
:
7433 type
= AST::Literal::RAW_STRING
;
7434 literal_value
= t
->get_str ();
7435 lexer
.skip_token ();
7438 type
= AST::Literal::INT
;
7439 literal_value
= t
->get_str ();
7440 lexer
.skip_token ();
7443 type
= AST::Literal::FLOAT
;
7444 literal_value
= t
->get_str ();
7445 lexer
.skip_token ();
7447 // case BOOL_LITERAL
7448 // use true and false keywords rather than "bool literal" Rust terminology
7450 type
= AST::Literal::BOOL
;
7451 literal_value
= Values::Keywords::TRUE_LITERAL
;
7452 lexer
.skip_token ();
7455 type
= AST::Literal::BOOL
;
7456 literal_value
= Values::Keywords::FALSE_LITERAL
;
7457 lexer
.skip_token ();
7460 // error - cannot be a literal expr
7461 add_error (Error (t
->get_locus (),
7462 "unexpected token %qs when parsing literal expression",
7463 t
->get_token_description ()));
7469 // create literal based on stuff in switch
7470 return std::unique_ptr
<AST::LiteralExpr
> (
7471 new AST::LiteralExpr (std::move (literal_value
), std::move (type
),
7472 t
->get_type_hint (), std::move (outer_attrs
),
7476 template <typename ManagedTokenSource
>
7477 std::unique_ptr
<AST::BoxExpr
>
7478 Parser
<ManagedTokenSource
>::parse_box_expr (AST::AttrVec outer_attrs
,
7479 location_t pratt_parsed_loc
)
7481 location_t locus
= pratt_parsed_loc
;
7482 if (locus
== UNKNOWN_LOCATION
)
7484 locus
= lexer
.peek_token ()->get_locus ();
7488 ParseRestrictions restrictions
;
7489 restrictions
.expr_can_be_null
= false;
7491 std::unique_ptr
<AST::Expr
> expr
= parse_expr (AST::AttrVec (), restrictions
);
7493 return std::unique_ptr
<AST::BoxExpr
> (
7494 new AST::BoxExpr (std::move (expr
), std::move (outer_attrs
), locus
));
7497 // Parses a return expression (including any expression to return).
7498 template <typename ManagedTokenSource
>
7499 std::unique_ptr
<AST::ReturnExpr
>
7500 Parser
<ManagedTokenSource
>::parse_return_expr (AST::AttrVec outer_attrs
,
7501 location_t pratt_parsed_loc
)
7503 location_t locus
= pratt_parsed_loc
;
7504 if (locus
== UNKNOWN_LOCATION
)
7506 locus
= lexer
.peek_token ()->get_locus ();
7507 skip_token (RETURN_KW
);
7510 // parse expression to return, if it exists
7511 ParseRestrictions restrictions
;
7512 restrictions
.expr_can_be_null
= true;
7513 std::unique_ptr
<AST::Expr
> returned_expr
7514 = parse_expr (AST::AttrVec (), restrictions
);
7516 return std::unique_ptr
<AST::ReturnExpr
> (
7517 new AST::ReturnExpr (std::move (returned_expr
), std::move (outer_attrs
),
7521 /* Parses a break expression (including any label to break to AND any return
7523 template <typename ManagedTokenSource
>
7524 std::unique_ptr
<AST::BreakExpr
>
7525 Parser
<ManagedTokenSource
>::parse_break_expr (AST::AttrVec outer_attrs
,
7526 location_t pratt_parsed_loc
)
7528 location_t locus
= pratt_parsed_loc
;
7529 if (locus
== UNKNOWN_LOCATION
)
7531 locus
= lexer
.peek_token ()->get_locus ();
7535 auto parsed_label
= parse_lifetime (false);
7536 auto label
= (parsed_label
)
7537 ? tl::optional
<AST::Lifetime
> (parsed_label
.value ())
7540 // parse break return expression if it exists
7541 ParseRestrictions restrictions
;
7542 restrictions
.expr_can_be_null
= true;
7543 std::unique_ptr
<AST::Expr
> return_expr
7544 = parse_expr (AST::AttrVec (), restrictions
);
7546 return std::unique_ptr
<AST::BreakExpr
> (
7547 new AST::BreakExpr (std::move (label
), std::move (return_expr
),
7548 std::move (outer_attrs
), locus
));
7551 // Parses a continue expression (including any label to continue from).
7552 template <typename ManagedTokenSource
>
7553 std::unique_ptr
<AST::ContinueExpr
>
7554 Parser
<ManagedTokenSource
>::parse_continue_expr (AST::AttrVec outer_attrs
,
7555 location_t pratt_parsed_loc
)
7557 location_t locus
= pratt_parsed_loc
;
7558 if (locus
== UNKNOWN_LOCATION
)
7560 locus
= lexer
.peek_token ()->get_locus ();
7561 skip_token (CONTINUE
);
7564 auto parsed_label
= parse_lifetime (false);
7565 auto label
= (parsed_label
)
7566 ? tl::optional
<AST::Lifetime
> (parsed_label
.value ())
7569 return std::unique_ptr
<AST::ContinueExpr
> (
7570 new AST::ContinueExpr (std::move (label
), std::move (outer_attrs
), locus
));
7573 // Parses a loop label used in loop expressions.
7574 template <typename ManagedTokenSource
>
7575 tl::expected
<AST::LoopLabel
, ParseLoopLabelError
>
7576 Parser
<ManagedTokenSource
>::parse_loop_label (const_TokenPtr tok
)
7578 // parse lifetime - if doesn't exist, assume no label
7579 if (tok
->get_id () != LIFETIME
)
7581 // not necessarily an error
7582 return tl::unexpected
<ParseLoopLabelError
> (
7583 ParseLoopLabelError::NOT_LOOP_LABEL
);
7585 /* FIXME: check for named lifetime requirement here? or check in semantic
7586 * analysis phase? */
7587 AST::Lifetime label
= lifetime_from_token (tok
);
7589 if (!skip_token (COLON
))
7592 return tl::unexpected
<ParseLoopLabelError
> (
7593 ParseLoopLabelError::MISSING_COLON
);
7596 return tl::expected
<AST::LoopLabel
, ParseLoopLabelError
> (
7597 AST::LoopLabel (std::move (label
), tok
->get_locus ()));
7600 /* Parses an if expression of any kind, including with else, else if, else if
7601 * let, and neither. Note that any outer attributes will be ignored because if
7602 * expressions don't support them. */
7603 template <typename ManagedTokenSource
>
7604 std::unique_ptr
<AST::IfExpr
>
7605 Parser
<ManagedTokenSource
>::parse_if_expr (AST::AttrVec outer_attrs
,
7606 location_t pratt_parsed_loc
)
7608 // TODO: make having outer attributes an error?
7609 location_t locus
= pratt_parsed_loc
;
7610 if (locus
== UNKNOWN_LOCATION
)
7612 locus
= lexer
.peek_token ()->get_locus ();
7613 if (!skip_token (IF
))
7615 skip_after_end_block ();
7620 // detect accidental if let
7621 if (lexer
.peek_token ()->get_id () == LET
)
7623 Error
error (lexer
.peek_token ()->get_locus (),
7624 "if let expression probably exists, but is being parsed "
7625 "as an if expression. This may be a parser error");
7626 add_error (std::move (error
));
7632 /* parse required condition expr - HACK to prevent struct expr from being
7634 ParseRestrictions no_struct_expr
;
7635 no_struct_expr
.can_be_struct_expr
= false;
7636 std::unique_ptr
<AST::Expr
> condition
= parse_expr ({}, no_struct_expr
);
7637 if (condition
== nullptr)
7639 Error
error (lexer
.peek_token ()->get_locus (),
7640 "failed to parse condition expression in if expression");
7641 add_error (std::move (error
));
7647 // parse required block expr
7648 std::unique_ptr
<AST::BlockExpr
> if_body
= parse_block_expr ();
7649 if (if_body
== nullptr)
7651 Error
error (lexer
.peek_token ()->get_locus (),
7652 "failed to parse if body block expression in if expression");
7653 add_error (std::move (error
));
7659 // branch to parse end or else (and then else, else if, or else if let)
7660 if (lexer
.peek_token ()->get_id () != ELSE
)
7662 // single selection - end of if expression
7663 return std::unique_ptr
<AST::IfExpr
> (
7664 new AST::IfExpr (std::move (condition
), std::move (if_body
),
7665 std::move (outer_attrs
), locus
));
7669 // double or multiple selection - branch on end, else if, or else if let
7672 lexer
.skip_token ();
7674 // branch on whether next token is '{' or 'if'
7675 const_TokenPtr t
= lexer
.peek_token ();
7676 switch (t
->get_id ())
7679 // double selection - else
7680 // parse else block expr (required)
7681 std::unique_ptr
<AST::BlockExpr
> else_body
= parse_block_expr ();
7682 if (else_body
== nullptr)
7684 Error
error (lexer
.peek_token ()->get_locus (),
7685 "failed to parse else body block expression in "
7687 add_error (std::move (error
));
7693 return std::unique_ptr
<AST::IfExprConseqElse
> (
7694 new AST::IfExprConseqElse (std::move (condition
),
7695 std::move (if_body
),
7696 std::move (else_body
),
7697 std::move (outer_attrs
), locus
));
7700 // multiple selection - else if or else if let
7701 // branch on whether next token is 'let' or not
7702 if (lexer
.peek_token (1)->get_id () == LET
)
7704 // parse if let expr (required)
7705 std::unique_ptr
<AST::IfLetExpr
> if_let_expr
7706 = parse_if_let_expr ();
7707 if (if_let_expr
== nullptr)
7709 Error
error (lexer
.peek_token ()->get_locus (),
7710 "failed to parse (else) if let expression "
7711 "after if expression");
7712 add_error (std::move (error
));
7718 return std::unique_ptr
<AST::IfExprConseqElse
> (
7719 new AST::IfExprConseqElse (std::move (condition
),
7720 std::move (if_body
),
7721 std::move (if_let_expr
),
7722 std::move (outer_attrs
), locus
));
7726 // parse if expr (required)
7727 std::unique_ptr
<AST::IfExpr
> if_expr
= parse_if_expr ();
7728 if (if_expr
== nullptr)
7730 Error
error (lexer
.peek_token ()->get_locus (),
7731 "failed to parse (else) if expression after "
7733 add_error (std::move (error
));
7739 return std::unique_ptr
<AST::IfExprConseqElse
> (
7740 new AST::IfExprConseqElse (std::move (condition
),
7741 std::move (if_body
),
7742 std::move (if_expr
),
7743 std::move (outer_attrs
), locus
));
7747 // error - invalid token
7748 add_error (Error (t
->get_locus (),
7749 "unexpected token %qs after else in if expression",
7750 t
->get_token_description ()));
7758 /* Parses an if let expression of any kind, including with else, else if, else
7759 * if let, and none. Note that any outer attributes will be ignored as if let
7760 * expressions don't support them. */
7761 template <typename ManagedTokenSource
>
7762 std::unique_ptr
<AST::IfLetExpr
>
7763 Parser
<ManagedTokenSource
>::parse_if_let_expr (AST::AttrVec outer_attrs
,
7764 location_t pratt_parsed_loc
)
7766 // TODO: make having outer attributes an error?
7767 location_t locus
= pratt_parsed_loc
;
7768 if (locus
== UNKNOWN_LOCATION
)
7770 locus
= lexer
.peek_token ()->get_locus ();
7771 if (!skip_token (IF
))
7773 skip_after_end_block ();
7778 // detect accidental if expr parsed as if let expr
7779 if (lexer
.peek_token ()->get_id () != LET
)
7781 Error
error (lexer
.peek_token ()->get_locus (),
7782 "if expression probably exists, but is being parsed as an "
7783 "if let expression. This may be a parser error");
7784 add_error (std::move (error
));
7789 lexer
.skip_token ();
7791 // parse match arm patterns (which are required)
7792 std::vector
<std::unique_ptr
<AST::Pattern
>> match_arm_patterns
7793 = parse_match_arm_patterns (EQUAL
);
7794 if (match_arm_patterns
.empty ())
7797 lexer
.peek_token ()->get_locus (),
7798 "failed to parse any match arm patterns in if let expression");
7799 add_error (std::move (error
));
7805 if (!skip_token (EQUAL
))
7811 // parse expression (required) - HACK to prevent struct expr being parsed
7812 ParseRestrictions no_struct_expr
;
7813 no_struct_expr
.can_be_struct_expr
= false;
7814 std::unique_ptr
<AST::Expr
> scrutinee_expr
= parse_expr ({}, no_struct_expr
);
7815 if (scrutinee_expr
== nullptr)
7817 Error
error (lexer
.peek_token ()->get_locus (),
7818 "failed to parse scrutinee expression in if let expression");
7819 add_error (std::move (error
));
7824 /* TODO: check for expression not being a struct expression or lazy boolean
7825 * expression here? or actually probably in semantic analysis. */
7827 // parse block expression (required)
7828 std::unique_ptr
<AST::BlockExpr
> if_let_body
= parse_block_expr ();
7829 if (if_let_body
== nullptr)
7832 lexer
.peek_token ()->get_locus (),
7833 "failed to parse if let body block expression in if let expression");
7834 add_error (std::move (error
));
7840 // branch to parse end or else (and then else, else if, or else if let)
7841 if (lexer
.peek_token ()->get_id () != ELSE
)
7843 // single selection - end of if let expression
7844 return std::unique_ptr
<AST::IfLetExpr
> (
7845 new AST::IfLetExpr (std::move (match_arm_patterns
),
7846 std::move (scrutinee_expr
), std::move (if_let_body
),
7847 std::move (outer_attrs
), locus
));
7851 // double or multiple selection - branch on end, else if, or else if let
7854 lexer
.skip_token ();
7856 // branch on whether next token is '{' or 'if'
7857 const_TokenPtr t
= lexer
.peek_token ();
7858 switch (t
->get_id ())
7861 // double selection - else
7862 // parse else block expr (required)
7863 std::unique_ptr
<AST::BlockExpr
> else_body
= parse_block_expr ();
7864 if (else_body
== nullptr)
7866 Error
error (lexer
.peek_token ()->get_locus (),
7867 "failed to parse else body block expression in "
7868 "if let expression");
7869 add_error (std::move (error
));
7875 return std::unique_ptr
<AST::IfLetExprConseqElse
> (
7876 new AST::IfLetExprConseqElse (std::move (match_arm_patterns
),
7877 std::move (scrutinee_expr
),
7878 std::move (if_let_body
),
7879 std::move (else_body
),
7880 std::move (outer_attrs
), locus
));
7883 // multiple selection - else if or else if let
7884 // branch on whether next token is 'let' or not
7885 if (lexer
.peek_token (1)->get_id () == LET
)
7887 // parse if let expr (required)
7888 std::unique_ptr
<AST::IfLetExpr
> if_let_expr
7889 = parse_if_let_expr ();
7890 if (if_let_expr
== nullptr)
7892 Error
error (lexer
.peek_token ()->get_locus (),
7893 "failed to parse (else) if let expression "
7894 "after if let expression");
7895 add_error (std::move (error
));
7901 return std::unique_ptr
<AST::IfLetExprConseqElse
> (
7902 new AST::IfLetExprConseqElse (
7903 std::move (match_arm_patterns
), std::move (scrutinee_expr
),
7904 std::move (if_let_body
), std::move (if_let_expr
),
7905 std::move (outer_attrs
), locus
));
7909 // parse if expr (required)
7910 std::unique_ptr
<AST::IfExpr
> if_expr
= parse_if_expr ();
7911 if (if_expr
== nullptr)
7913 Error
error (lexer
.peek_token ()->get_locus (),
7914 "failed to parse (else) if expression after "
7915 "if let expression");
7916 add_error (std::move (error
));
7922 return std::unique_ptr
<AST::IfLetExprConseqElse
> (
7923 new AST::IfLetExprConseqElse (
7924 std::move (match_arm_patterns
), std::move (scrutinee_expr
),
7925 std::move (if_let_body
), std::move (if_expr
),
7926 std::move (outer_attrs
), locus
));
7930 // error - invalid token
7932 Error (t
->get_locus (),
7933 "unexpected token %qs after else in if let expression",
7934 t
->get_token_description ()));
7942 /* TODO: possibly decide on different method of handling label (i.e. not
7945 /* Parses a "loop" infinite loop expression. Label is not parsed and should be
7946 * parsed via parse_labelled_loop_expr, which would call this. */
7947 template <typename ManagedTokenSource
>
7948 std::unique_ptr
<AST::LoopExpr
>
7949 Parser
<ManagedTokenSource
>::parse_loop_expr (AST::AttrVec outer_attrs
,
7950 tl::optional
<AST::LoopLabel
> label
,
7951 location_t pratt_parsed_loc
)
7953 location_t locus
= pratt_parsed_loc
;
7954 if (locus
== UNKNOWN_LOCATION
)
7957 locus
= label
->get_locus ();
7959 locus
= lexer
.peek_token ()->get_locus ();
7961 if (!skip_token (LOOP
))
7963 skip_after_end_block ();
7970 locus
= label
->get_locus ();
7973 // parse loop body, which is required
7974 std::unique_ptr
<AST::BlockExpr
> loop_body
= parse_block_expr ();
7975 if (loop_body
== nullptr)
7977 Error
error (lexer
.peek_token ()->get_locus (),
7978 "could not parse loop body in (infinite) loop expression");
7979 add_error (std::move (error
));
7984 return std::unique_ptr
<AST::LoopExpr
> (
7985 new AST::LoopExpr (std::move (loop_body
), locus
, std::move (label
),
7986 std::move (outer_attrs
)));
7989 /* Parses a "while" loop expression. Label is not parsed and should be parsed
7990 * via parse_labelled_loop_expr, which would call this. */
7991 template <typename ManagedTokenSource
>
7992 std::unique_ptr
<AST::WhileLoopExpr
>
7993 Parser
<ManagedTokenSource
>::parse_while_loop_expr (
7994 AST::AttrVec outer_attrs
, tl::optional
<AST::LoopLabel
> label
,
7995 location_t pratt_parsed_loc
)
7997 location_t locus
= pratt_parsed_loc
;
7998 if (locus
== UNKNOWN_LOCATION
)
8001 locus
= label
->get_locus ();
8003 locus
= lexer
.peek_token ()->get_locus ();
8005 if (!skip_token (WHILE
))
8007 skip_after_end_block ();
8014 locus
= label
->get_locus ();
8017 // ensure it isn't a while let loop
8018 if (lexer
.peek_token ()->get_id () == LET
)
8020 Error
error (lexer
.peek_token ()->get_locus (),
8021 "appears to be while let loop but is being parsed by "
8022 "while loop - this may be a compiler issue");
8023 add_error (std::move (error
));
8029 // parse loop predicate (required) with HACK to prevent struct expr parsing
8030 ParseRestrictions no_struct_expr
;
8031 no_struct_expr
.can_be_struct_expr
= false;
8032 std::unique_ptr
<AST::Expr
> predicate
= parse_expr ({}, no_struct_expr
);
8033 if (predicate
== nullptr)
8035 Error
error (lexer
.peek_token ()->get_locus (),
8036 "failed to parse predicate expression in while loop");
8037 add_error (std::move (error
));
8042 /* TODO: check that it isn't struct expression here? actually, probably in
8043 * semantic analysis */
8045 // parse loop body (required)
8046 std::unique_ptr
<AST::BlockExpr
> body
= parse_block_expr ();
8047 if (body
== nullptr)
8049 Error
error (lexer
.peek_token ()->get_locus (),
8050 "failed to parse loop body block expression in while loop");
8051 add_error (std::move (error
));
8057 return std::unique_ptr
<AST::WhileLoopExpr
> (
8058 new AST::WhileLoopExpr (std::move (predicate
), std::move (body
), locus
,
8059 std::move (label
), std::move (outer_attrs
)));
8062 /* Parses a "while let" loop expression. Label is not parsed and should be
8063 * parsed via parse_labelled_loop_expr, which would call this. */
8064 template <typename ManagedTokenSource
>
8065 std::unique_ptr
<AST::WhileLetLoopExpr
>
8066 Parser
<ManagedTokenSource
>::parse_while_let_loop_expr (
8067 AST::AttrVec outer_attrs
, tl::optional
<AST::LoopLabel
> label
)
8069 location_t locus
= UNKNOWN_LOCATION
;
8071 locus
= label
->get_locus ();
8073 locus
= lexer
.peek_token ()->get_locus ();
8074 maybe_skip_token (WHILE
);
8076 /* check for possible accidental recognition of a while loop as a while let
8078 if (lexer
.peek_token ()->get_id () != LET
)
8080 Error
error (lexer
.peek_token ()->get_locus (),
8081 "appears to be a while loop but is being parsed by "
8082 "while let loop - this may be a compiler issue");
8083 add_error (std::move (error
));
8088 // as this token is definitely let now, save the computation of comparison
8089 lexer
.skip_token ();
8091 // parse predicate patterns
8092 std::vector
<std::unique_ptr
<AST::Pattern
>> predicate_patterns
8093 = parse_match_arm_patterns (EQUAL
);
8094 // TODO: have to ensure that there is at least 1 pattern?
8096 if (!skip_token (EQUAL
))
8102 /* parse predicate expression, which is required (and HACK to prevent struct
8104 ParseRestrictions no_struct_expr
;
8105 no_struct_expr
.can_be_struct_expr
= false;
8106 std::unique_ptr
<AST::Expr
> predicate_expr
= parse_expr ({}, no_struct_expr
);
8107 if (predicate_expr
== nullptr)
8109 Error
error (lexer
.peek_token ()->get_locus (),
8110 "failed to parse predicate expression in while let loop");
8111 add_error (std::move (error
));
8116 /* TODO: ensure that struct expression is not parsed? Actually, probably in
8117 * semantic analysis. */
8119 // parse loop body, which is required
8120 std::unique_ptr
<AST::BlockExpr
> body
= parse_block_expr ();
8121 if (body
== nullptr)
8123 Error
error (lexer
.peek_token ()->get_locus (),
8124 "failed to parse block expr (loop body) of while let loop");
8125 add_error (std::move (error
));
8131 return std::unique_ptr
<AST::WhileLetLoopExpr
> (new AST::WhileLetLoopExpr (
8132 std::move (predicate_patterns
), std::move (predicate_expr
),
8133 std::move (body
), locus
, std::move (label
), std::move (outer_attrs
)));
8136 /* Parses a "for" iterative loop. Label is not parsed and should be parsed via
8137 * parse_labelled_loop_expr, which would call this. */
8138 template <typename ManagedTokenSource
>
8139 std::unique_ptr
<AST::ForLoopExpr
>
8140 Parser
<ManagedTokenSource
>::parse_for_loop_expr (
8141 AST::AttrVec outer_attrs
, tl::optional
<AST::LoopLabel
> label
)
8143 location_t locus
= UNKNOWN_LOCATION
;
8145 locus
= label
->get_locus ();
8147 locus
= lexer
.peek_token ()->get_locus ();
8148 maybe_skip_token (FOR
);
8150 // parse pattern, which is required
8151 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
8152 if (pattern
== nullptr)
8154 Error
error (lexer
.peek_token ()->get_locus (),
8155 "failed to parse iterator pattern in for loop");
8156 add_error (std::move (error
));
8162 if (!skip_token (IN
))
8168 /* parse iterator expression, which is required - also HACK to prevent
8170 ParseRestrictions no_struct_expr
;
8171 no_struct_expr
.can_be_struct_expr
= false;
8172 std::unique_ptr
<AST::Expr
> expr
= parse_expr ({}, no_struct_expr
);
8173 if (expr
== nullptr)
8175 Error
error (lexer
.peek_token ()->get_locus (),
8176 "failed to parse iterator expression in for loop");
8177 add_error (std::move (error
));
8182 // TODO: check to ensure this isn't struct expr? Or in semantic analysis.
8184 // parse loop body, which is required
8185 std::unique_ptr
<AST::BlockExpr
> body
= parse_block_expr ();
8186 if (body
== nullptr)
8188 Error
error (lexer
.peek_token ()->get_locus (),
8189 "failed to parse loop body block expression in for loop");
8190 add_error (std::move (error
));
8196 return std::unique_ptr
<AST::ForLoopExpr
> (
8197 new AST::ForLoopExpr (std::move (pattern
), std::move (expr
),
8198 std::move (body
), locus
, std::move (label
),
8199 std::move (outer_attrs
)));
8202 // Parses a loop expression with label (any kind of loop - disambiguates).
8203 template <typename ManagedTokenSource
>
8204 std::unique_ptr
<AST::Expr
>
8205 Parser
<ManagedTokenSource
>::parse_labelled_loop_expr (const_TokenPtr tok
,
8206 AST::AttrVec outer_attrs
)
8208 /* TODO: decide whether it should not work if there is no label, or parse it
8209 * with no label at the moment, I will make it not work with no label
8210 * because that's the implication. */
8212 if (tok
->get_id () != LIFETIME
)
8214 Error
error (tok
->get_locus (),
8215 "expected lifetime in labelled loop expr (to parse loop "
8216 "label) - found %qs",
8217 tok
->get_token_description ());
8218 add_error (std::move (error
));
8224 // parse loop label (required)
8225 // TODO: Convert this return type to tl::expected instead of tl::optional
8226 auto parsed_label
= parse_loop_label (tok
);
8229 Error
error (lexer
.peek_token ()->get_locus (),
8230 "failed to parse loop label in labelled loop expr");
8231 add_error (std::move (error
));
8237 auto label
= parsed_label
8238 ? tl::optional
<AST::LoopLabel
> (parsed_label
.value ())
8241 // branch on next token
8242 const_TokenPtr t
= lexer
.peek_token ();
8243 switch (t
->get_id ())
8246 return parse_loop_expr (std::move (outer_attrs
), std::move (label
));
8248 return parse_for_loop_expr (std::move (outer_attrs
), std::move (label
));
8250 // further disambiguate into while vs while let
8251 if (lexer
.peek_token (1)->get_id () == LET
)
8253 return parse_while_let_loop_expr (std::move (outer_attrs
),
8258 return parse_while_loop_expr (std::move (outer_attrs
),
8262 return parse_block_expr (std::move (outer_attrs
), std::move (label
));
8265 add_error (Error (t
->get_locus (),
8266 "unexpected token %qs when parsing labelled loop",
8267 t
->get_token_description ()));
8274 // Parses a match expression.
8275 template <typename ManagedTokenSource
>
8276 std::unique_ptr
<AST::MatchExpr
>
8277 Parser
<ManagedTokenSource
>::parse_match_expr (AST::AttrVec outer_attrs
,
8278 location_t pratt_parsed_loc
)
8280 location_t locus
= pratt_parsed_loc
;
8281 if (locus
== UNKNOWN_LOCATION
)
8283 locus
= lexer
.peek_token ()->get_locus ();
8284 skip_token (MATCH_KW
);
8287 /* parse scrutinee expression, which is required (and HACK to prevent struct
8289 ParseRestrictions no_struct_expr
;
8290 no_struct_expr
.can_be_struct_expr
= false;
8291 std::unique_ptr
<AST::Expr
> scrutinee
= parse_expr ({}, no_struct_expr
);
8292 if (scrutinee
== nullptr)
8294 Error
error (lexer
.peek_token ()->get_locus (),
8295 "failed to parse scrutinee expression in match expression");
8296 add_error (std::move (error
));
8301 /* TODO: check for scrutinee expr not being struct expr? or do so in
8302 * semantic analysis */
8304 if (!skip_token (LEFT_CURLY
))
8310 // parse inner attributes (if they exist)
8311 AST::AttrVec inner_attrs
= parse_inner_attributes ();
8313 // parse match arms (if they exist)
8314 // std::vector<std::unique_ptr<AST::MatchCase> > match_arms;
8315 std::vector
<AST::MatchCase
> match_arms
;
8317 // parse match cases
8318 while (lexer
.peek_token ()->get_id () != RIGHT_CURLY
)
8320 // parse match arm itself, which is required
8321 AST::MatchArm arm
= parse_match_arm ();
8322 if (arm
.is_error ())
8324 // TODO is this worth throwing everything away?
8325 Error
error (lexer
.peek_token ()->get_locus (),
8326 "failed to parse match arm in match arms");
8327 add_error (std::move (error
));
8332 if (!skip_token (MATCH_ARROW
))
8334 // skip after somewhere?
8335 // TODO is returning here a good idea? or is break better?
8339 ParseRestrictions restrictions
;
8340 restrictions
.expr_can_be_stmt
= true;
8342 std::unique_ptr
<AST::Expr
> expr
= parse_expr ({}, restrictions
);
8344 if (expr
== nullptr)
8346 Error
error (lexer
.peek_token ()->get_locus (),
8347 "failed to parse expr in match arm in match expr");
8348 add_error (std::move (error
));
8354 bool is_expr_without_block
= expr
->is_expr_without_block ();
8356 match_arms
.push_back (AST::MatchCase (std::move (arm
), std::move (expr
)));
8358 // handle comma presence
8359 if (lexer
.peek_token ()->get_id () != COMMA
)
8361 if (!is_expr_without_block
)
8363 // allowed even if not final case
8366 else if (is_expr_without_block
8367 && lexer
.peek_token ()->get_id () != RIGHT_CURLY
)
8369 // not allowed if not final case
8370 Error
error (lexer
.peek_token ()->get_locus (),
8371 "exprwithoutblock requires comma after match case "
8372 "expression in match arm (if not final case)");
8373 add_error (std::move (error
));
8379 // otherwise, must be final case, so fine
8383 lexer
.skip_token ();
8386 if (!skip_token (RIGHT_CURLY
))
8392 match_arms
.shrink_to_fit ();
8394 return std::unique_ptr
<AST::MatchExpr
> (
8395 new AST::MatchExpr (std::move (scrutinee
), std::move (match_arms
),
8396 std::move (inner_attrs
), std::move (outer_attrs
),
8400 // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
8401 template <typename ManagedTokenSource
>
8403 Parser
<ManagedTokenSource
>::parse_match_arm ()
8405 // parse optional outer attributes
8406 AST::AttrVec outer_attrs
= parse_outer_attributes ();
8409 rust_debug ("about to start parsing match arm patterns");
8411 // break early if find right curly
8412 if (lexer
.peek_token ()->get_id () == RIGHT_CURLY
)
8415 return AST::MatchArm::create_error ();
8418 // parse match arm patterns - at least 1 is required
8419 std::vector
<std::unique_ptr
<AST::Pattern
>> match_arm_patterns
8420 = parse_match_arm_patterns (RIGHT_CURLY
);
8421 if (match_arm_patterns
.empty ())
8423 Error
error (lexer
.peek_token ()->get_locus (),
8424 "failed to parse any patterns in match arm");
8425 add_error (std::move (error
));
8428 return AST::MatchArm::create_error ();
8432 rust_debug ("successfully parsed match arm patterns");
8434 // parse match arm guard expr if it exists
8435 std::unique_ptr
<AST::Expr
> guard_expr
= nullptr;
8436 if (lexer
.peek_token ()->get_id () == IF
)
8438 lexer
.skip_token ();
8440 guard_expr
= parse_expr ();
8441 if (guard_expr
== nullptr)
8443 Error
error (lexer
.peek_token ()->get_locus (),
8444 "failed to parse guard expression in match arm");
8445 add_error (std::move (error
));
8448 return AST::MatchArm::create_error ();
8453 rust_debug ("successfully parsed match arm");
8455 return AST::MatchArm (std::move (match_arm_patterns
),
8456 lexer
.peek_token ()->get_locus (),
8457 std::move (guard_expr
), std::move (outer_attrs
));
8460 /* Parses the patterns used in a match arm. End token id is the id of the
8461 * token that would exist after the patterns are done (e.g. '}' for match
8462 * expr, '=' for if let and while let). */
8463 template <typename ManagedTokenSource
>
8464 std::vector
<std::unique_ptr
<AST::Pattern
>>
8465 Parser
<ManagedTokenSource
>::parse_match_arm_patterns (TokenId end_token_id
)
8467 // skip optional leading '|'
8468 if (lexer
.peek_token ()->get_id () == PIPE
)
8469 lexer
.skip_token ();
8470 /* TODO: do I even need to store the result of this? can't be used.
8471 * If semantically different, I need a wrapped "match arm patterns" object
8474 std::vector
<std::unique_ptr
<AST::Pattern
>> patterns
;
8476 // quick break out if end_token_id
8477 if (lexer
.peek_token ()->get_id () == end_token_id
)
8480 // parse required pattern - if doesn't exist, return empty
8481 std::unique_ptr
<AST::Pattern
> initial_pattern
= parse_pattern ();
8482 if (initial_pattern
== nullptr)
8484 // FIXME: should this be an error?
8487 patterns
.push_back (std::move (initial_pattern
));
8490 rust_debug ("successfully parsed initial match arm pattern");
8492 // parse new patterns as long as next char is '|'
8493 const_TokenPtr t
= lexer
.peek_token ();
8494 while (t
->get_id () == PIPE
)
8497 lexer
.skip_token ();
8499 // break if hit end token id
8500 if (lexer
.peek_token ()->get_id () == end_token_id
)
8504 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
8505 if (pattern
== nullptr)
8508 Error
error (lexer
.peek_token ()->get_locus (),
8509 "failed to parse pattern in match arm patterns");
8510 add_error (std::move (error
));
8516 patterns
.push_back (std::move (pattern
));
8518 t
= lexer
.peek_token ();
8521 patterns
.shrink_to_fit ();
8526 // Parses an async block expression.
8527 template <typename ManagedTokenSource
>
8528 std::unique_ptr
<AST::AsyncBlockExpr
>
8529 Parser
<ManagedTokenSource
>::parse_async_block_expr (AST::AttrVec outer_attrs
)
8531 location_t locus
= lexer
.peek_token ()->get_locus ();
8534 // detect optional move token
8535 bool has_move
= false;
8536 if (lexer
.peek_token ()->get_id () == MOVE
)
8538 lexer
.skip_token ();
8542 // parse block expression (required)
8543 std::unique_ptr
<AST::BlockExpr
> block_expr
= parse_block_expr ();
8544 if (block_expr
== nullptr)
8547 lexer
.peek_token ()->get_locus (),
8548 "failed to parse block expression of async block expression");
8549 add_error (std::move (error
));
8555 return std::unique_ptr
<AST::AsyncBlockExpr
> (
8556 new AST::AsyncBlockExpr (std::move (block_expr
), has_move
,
8557 std::move (outer_attrs
), locus
));
8560 // Parses an unsafe block expression.
8561 template <typename ManagedTokenSource
>
8562 std::unique_ptr
<AST::UnsafeBlockExpr
>
8563 Parser
<ManagedTokenSource
>::parse_unsafe_block_expr (
8564 AST::AttrVec outer_attrs
, location_t pratt_parsed_loc
)
8566 location_t locus
= pratt_parsed_loc
;
8567 if (locus
== UNKNOWN_LOCATION
)
8569 locus
= lexer
.peek_token ()->get_locus ();
8570 skip_token (UNSAFE
);
8573 // parse block expression (required)
8574 std::unique_ptr
<AST::BlockExpr
> block_expr
= parse_block_expr ();
8575 if (block_expr
== nullptr)
8578 lexer
.peek_token ()->get_locus (),
8579 "failed to parse block expression of unsafe block expression");
8580 add_error (std::move (error
));
8586 return std::unique_ptr
<AST::UnsafeBlockExpr
> (
8587 new AST::UnsafeBlockExpr (std::move (block_expr
), std::move (outer_attrs
),
8591 // Parses an array definition expression.
8592 template <typename ManagedTokenSource
>
8593 std::unique_ptr
<AST::ArrayExpr
>
8594 Parser
<ManagedTokenSource
>::parse_array_expr (AST::AttrVec outer_attrs
,
8595 location_t pratt_parsed_loc
)
8597 location_t locus
= pratt_parsed_loc
;
8598 if (locus
== UNKNOWN_LOCATION
)
8600 locus
= lexer
.peek_token ()->get_locus ();
8601 skip_token (LEFT_SQUARE
);
8604 // parse optional inner attributes
8605 AST::AttrVec inner_attrs
= parse_inner_attributes ();
8607 // parse the "array elements" section, which is optional
8608 if (lexer
.peek_token ()->get_id () == RIGHT_SQUARE
)
8610 // no array elements
8611 lexer
.skip_token ();
8613 std::vector
<std::unique_ptr
<AST::Expr
>> exprs
;
8615 = std::make_unique
<AST::ArrayElemsValues
> (std::move (exprs
), locus
);
8616 return std::make_unique
<AST::ArrayExpr
> (std::move (array_elems
),
8617 std::move (inner_attrs
),
8618 std::move (outer_attrs
), locus
);
8622 // should have array elements
8623 // parse initial expression, which is required for either
8624 std::unique_ptr
<AST::Expr
> initial_expr
= parse_expr ();
8625 if (initial_expr
== nullptr)
8627 Error
error (lexer
.peek_token ()->get_locus (),
8628 "could not parse expression in array expression "
8629 "(even though arrayelems seems to be present)");
8630 add_error (std::move (error
));
8636 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
8639 lexer
.skip_token ();
8641 // parse copy amount expression (required)
8642 std::unique_ptr
<AST::Expr
> copy_amount
= parse_expr ();
8643 if (copy_amount
== nullptr)
8645 Error
error (lexer
.peek_token ()->get_locus (),
8646 "could not parse copy amount expression in array "
8647 "expression (arrayelems)");
8648 add_error (std::move (error
));
8654 skip_token (RIGHT_SQUARE
);
8656 std::unique_ptr
<AST::ArrayElemsCopied
> copied_array_elems (
8657 new AST::ArrayElemsCopied (std::move (initial_expr
),
8658 std::move (copy_amount
), locus
));
8659 return std::unique_ptr
<AST::ArrayExpr
> (
8660 new AST::ArrayExpr (std::move (copied_array_elems
),
8661 std::move (inner_attrs
),
8662 std::move (outer_attrs
), locus
));
8664 else if (lexer
.peek_token ()->get_id () == RIGHT_SQUARE
)
8666 // single-element array expression
8667 std::vector
<std::unique_ptr
<AST::Expr
>> exprs
;
8669 exprs
.push_back (std::move (initial_expr
));
8670 exprs
.shrink_to_fit ();
8672 skip_token (RIGHT_SQUARE
);
8674 std::unique_ptr
<AST::ArrayElemsValues
> array_elems (
8675 new AST::ArrayElemsValues (std::move (exprs
), locus
));
8676 return std::unique_ptr
<AST::ArrayExpr
> (
8677 new AST::ArrayExpr (std::move (array_elems
),
8678 std::move (inner_attrs
),
8679 std::move (outer_attrs
), locus
));
8681 else if (lexer
.peek_token ()->get_id () == COMMA
)
8683 // multi-element array expression (or trailing comma)
8684 std::vector
<std::unique_ptr
<AST::Expr
>> exprs
;
8685 exprs
.push_back (std::move (initial_expr
));
8687 const_TokenPtr t
= lexer
.peek_token ();
8688 while (t
->get_id () == COMMA
)
8690 lexer
.skip_token ();
8692 // quick break if right square bracket
8693 if (lexer
.peek_token ()->get_id () == RIGHT_SQUARE
)
8696 // parse expression (required)
8697 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
8698 if (expr
== nullptr)
8700 Error
error (lexer
.peek_token ()->get_locus (),
8701 "failed to parse element in array expression");
8702 add_error (std::move (error
));
8707 exprs
.push_back (std::move (expr
));
8709 t
= lexer
.peek_token ();
8712 skip_token (RIGHT_SQUARE
);
8714 exprs
.shrink_to_fit ();
8716 std::unique_ptr
<AST::ArrayElemsValues
> array_elems (
8717 new AST::ArrayElemsValues (std::move (exprs
), locus
));
8718 return std::unique_ptr
<AST::ArrayExpr
> (
8719 new AST::ArrayExpr (std::move (array_elems
),
8720 std::move (inner_attrs
),
8721 std::move (outer_attrs
), locus
));
8726 Error
error (lexer
.peek_token ()->get_locus (),
8727 "unexpected token %qs in array expression (arrayelems)",
8728 lexer
.peek_token ()->get_token_description ());
8729 add_error (std::move (error
));
8737 // Parses a single parameter used in a closure definition.
8738 template <typename ManagedTokenSource
>
8740 Parser
<ManagedTokenSource
>::parse_closure_param ()
8742 AST::AttrVec outer_attrs
= parse_outer_attributes ();
8744 // parse pattern (which is required)
8745 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern_no_alt ();
8746 if (pattern
== nullptr)
8748 // not necessarily an error
8749 return AST::ClosureParam::create_error ();
8752 // parse optional type of param
8753 std::unique_ptr
<AST::Type
> type
= nullptr;
8754 if (lexer
.peek_token ()->get_id () == COLON
)
8756 lexer
.skip_token ();
8758 // parse type, which is now required
8759 type
= parse_type ();
8760 if (type
== nullptr)
8762 Error
error (lexer
.peek_token ()->get_locus (),
8763 "failed to parse type in closure parameter");
8764 add_error (std::move (error
));
8767 return AST::ClosureParam::create_error ();
8771 location_t loc
= pattern
->get_locus ();
8772 return AST::ClosureParam (std::move (pattern
), loc
, std::move (type
),
8773 std::move (outer_attrs
));
8776 // Parses a grouped or tuple expression (disambiguates).
8777 template <typename ManagedTokenSource
>
8778 std::unique_ptr
<AST::ExprWithoutBlock
>
8779 Parser
<ManagedTokenSource
>::parse_grouped_or_tuple_expr (
8780 AST::AttrVec outer_attrs
, location_t pratt_parsed_loc
)
8782 // adjustment to allow Pratt parsing to reuse function without copy-paste
8783 location_t locus
= pratt_parsed_loc
;
8784 if (locus
== UNKNOWN_LOCATION
)
8786 locus
= lexer
.peek_token ()->get_locus ();
8787 skip_token (LEFT_PAREN
);
8790 // parse optional inner attributes
8791 AST::AttrVec inner_attrs
= parse_inner_attributes ();
8793 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
8795 // must be empty tuple
8796 lexer
.skip_token ();
8798 // create tuple with empty tuple elems
8799 return std::unique_ptr
<AST::TupleExpr
> (
8800 new AST::TupleExpr (std::vector
<std::unique_ptr
<AST::Expr
>> (),
8801 std::move (inner_attrs
), std::move (outer_attrs
),
8805 // parse first expression (required)
8806 std::unique_ptr
<AST::Expr
> first_expr
= parse_expr ();
8807 if (first_expr
== nullptr)
8809 Error
error (lexer
.peek_token ()->get_locus (),
8810 "failed to parse expression in grouped or tuple expression");
8811 add_error (std::move (error
));
8813 // skip after somewhere?
8817 // detect whether grouped expression with right parentheses as next token
8818 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
8820 // must be grouped expr
8821 lexer
.skip_token ();
8823 // create grouped expr
8824 return std::unique_ptr
<AST::GroupedExpr
> (
8825 new AST::GroupedExpr (std::move (first_expr
), std::move (inner_attrs
),
8826 std::move (outer_attrs
), locus
));
8828 else if (lexer
.peek_token ()->get_id () == COMMA
)
8831 std::vector
<std::unique_ptr
<AST::Expr
>> exprs
;
8832 exprs
.push_back (std::move (first_expr
));
8834 // parse potential other tuple exprs
8835 const_TokenPtr t
= lexer
.peek_token ();
8836 while (t
->get_id () == COMMA
)
8838 lexer
.skip_token ();
8840 // break out if right paren
8841 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
8844 // parse expr, which is now required
8845 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
8846 if (expr
== nullptr)
8848 Error
error (lexer
.peek_token ()->get_locus (),
8849 "failed to parse expr in tuple expr");
8850 add_error (std::move (error
));
8855 exprs
.push_back (std::move (expr
));
8857 t
= lexer
.peek_token ();
8861 skip_token (RIGHT_PAREN
);
8863 return std::unique_ptr
<AST::TupleExpr
> (
8864 new AST::TupleExpr (std::move (exprs
), std::move (inner_attrs
),
8865 std::move (outer_attrs
), locus
));
8870 const_TokenPtr t
= lexer
.peek_token ();
8871 Error
error (t
->get_locus (),
8872 "unexpected token %qs in grouped or tuple expression "
8873 "(parenthesised expression) - expected %<)%> for grouped "
8874 "expr and %<,%> for tuple expr",
8875 t
->get_token_description ());
8876 add_error (std::move (error
));
8883 // Parses a type (will further disambiguate any type).
8884 template <typename ManagedTokenSource
>
8885 std::unique_ptr
<AST::Type
>
8886 Parser
<ManagedTokenSource
>::parse_type (bool save_errors
)
8888 /* rules for all types:
8890 * SliceType: '[' Type ']'
8892 * MacroInvocation: SimplePath '!' DelimTokenTree
8893 * ParenthesisedType: '(' Type ')'
8894 * ImplTraitType: 'impl' TypeParamBounds
8895 * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'?
8896 * TypeParamBound Lifetime | TraitBound
8897 * ImplTraitTypeOneBound: 'impl' TraitBound
8898 * TraitObjectType: 'dyn'? TypeParamBounds
8899 * TraitObjectTypeOneBound: 'dyn'? TraitBound
8900 * TraitBound '?'? ForLifetimes? TypePath | '(' '?'?
8901 * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes?
8902 * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
8903 * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )?
8905 * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>'
8907 * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment (
8908 * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']'
8909 * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds
8910 * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds
8911 * TupleType: '(' Type etc. - regular tuple stuff. Also
8912 * regular tuple vs parenthesised precedence
8914 * Disambiguate between macro and type path via type path being parsed, and
8915 * then if '!' found, convert type path to simple path for macro. Usual
8916 * disambiguation for tuple vs parenthesised. For ImplTraitType and
8917 * TraitObjectType individual disambiguations, they seem more like "special
8918 * cases", so probably just try to parse the more general ImplTraitType or
8919 * TraitObjectType and return OneBound versions if they satisfy those
8922 const_TokenPtr t
= lexer
.peek_token ();
8923 switch (t
->get_id ())
8926 // never type - can't be macro as no path beforehand
8927 lexer
.skip_token ();
8928 return std::unique_ptr
<AST::NeverType
> (
8929 new AST::NeverType (t
->get_locus ()));
8931 // slice type or array type - requires further disambiguation
8932 return parse_slice_or_array_type ();
8935 // qualified path in type
8936 AST::QualifiedPathInType path
= parse_qualified_path_in_type ();
8937 if (path
.is_error ())
8941 Error
error (t
->get_locus (),
8942 "failed to parse qualified path in type");
8943 add_error (std::move (error
));
8948 return std::unique_ptr
<AST::QualifiedPathInType
> (
8949 new AST::QualifiedPathInType (std::move (path
)));
8953 lexer
.skip_token ();
8954 return std::unique_ptr
<AST::InferredType
> (
8955 new AST::InferredType (t
->get_locus ()));
8958 return parse_raw_pointer_type ();
8959 case AMP
: // does this also include AMP_AMP?
8962 return parse_reference_type ();
8964 /* probably a lifetime bound, so probably type param bounds in
8965 * TraitObjectType */
8966 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
8967 = parse_type_param_bounds ();
8969 return std::unique_ptr
<AST::TraitObjectType
> (
8970 new AST::TraitObjectType (std::move (bounds
), t
->get_locus (),
8979 case SCOPE_RESOLUTION
: {
8980 // macro invocation or type path - requires further disambiguation.
8981 /* for parsing path component of each rule, perhaps parse it as a
8982 * typepath and attempt conversion to simplepath if a trailing '!' is
8984 /* Type path also includes TraitObjectTypeOneBound BUT if it starts
8985 * with it, it is exactly the same as a TypePath syntactically, so
8986 * this is a syntactical ambiguity. As such, the parser will parse it
8987 * as a TypePath. This, however, does not prevent TraitObjectType from
8988 * starting with a typepath. */
8990 // parse path as type path
8991 AST::TypePath path
= parse_type_path ();
8992 if (path
.is_error ())
8996 Error
error (t
->get_locus (),
8997 "failed to parse path as first component of type");
8998 add_error (std::move (error
));
9003 location_t locus
= path
.get_locus ();
9005 // branch on next token
9006 t
= lexer
.peek_token ();
9007 switch (t
->get_id ())
9011 // convert to simple path
9012 AST::SimplePath macro_path
= path
.as_simple_path ();
9013 if (macro_path
.is_empty ())
9017 Error
error (t
->get_locus (),
9018 "failed to parse simple path in macro "
9019 "invocation (for type)");
9020 add_error (std::move (error
));
9026 lexer
.skip_token ();
9028 AST::DelimTokenTree tok_tree
= parse_delim_token_tree ();
9030 return AST::MacroInvocation::Regular (
9031 AST::MacroInvocData (std::move (macro_path
),
9032 std::move (tok_tree
)),
9036 // type param bounds
9037 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
9039 // convert type path to trait bound
9040 std::unique_ptr
<AST::TraitBound
> path_bound (
9041 new AST::TraitBound (std::move (path
), locus
, false, false));
9042 bounds
.push_back (std::move (path_bound
));
9044 /* parse rest of bounds - FIXME: better way to find when to stop
9046 while (t
->get_id () == PLUS
)
9048 lexer
.skip_token ();
9050 // parse bound if it exists - if not, assume end of sequence
9051 std::unique_ptr
<AST::TypeParamBound
> bound
9052 = parse_type_param_bound ();
9053 if (bound
== nullptr)
9057 bounds
.push_back (std::move (bound
));
9059 t
= lexer
.peek_token ();
9062 return std::unique_ptr
<AST::TraitObjectType
> (
9063 new AST::TraitObjectType (std::move (bounds
), locus
, false));
9066 // assume that this is a type path and not an error
9067 return std::unique_ptr
<AST::TypePath
> (
9068 new AST::TypePath (std::move (path
)));
9072 /* tuple type or parenthesised type - requires further disambiguation
9073 * (the usual). ok apparently can be a parenthesised TraitBound too, so
9074 * could be TraitObjectTypeOneBound or TraitObjectType */
9075 return parse_paren_prefixed_type ();
9077 // TraitObjectTypeOneBound or BareFunctionType
9078 return parse_for_prefixed_type ();
9084 // bare function type (with no for lifetimes)
9085 return parse_bare_function_type (std::vector
<AST::LifetimeParam
> ());
9087 lexer
.skip_token ();
9088 if (lexer
.peek_token ()->get_id () == LIFETIME
)
9090 /* cannot be one bound because lifetime prevents it from being
9092 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
9093 = parse_type_param_bounds ();
9095 return std::unique_ptr
<AST::ImplTraitType
> (
9096 new AST::ImplTraitType (std::move (bounds
), t
->get_locus ()));
9100 // should be trait bound, so parse trait bound
9101 std::unique_ptr
<AST::TraitBound
> initial_bound
= parse_trait_bound ();
9102 if (initial_bound
== nullptr)
9106 Error
error (lexer
.peek_token ()->get_locus (),
9107 "failed to parse ImplTraitType initial bound");
9108 add_error (std::move (error
));
9114 location_t locus
= t
->get_locus ();
9116 // short cut if next token isn't '+'
9117 t
= lexer
.peek_token ();
9118 if (t
->get_id () != PLUS
)
9120 // convert trait bound to value object
9121 AST::TraitBound
value_bound (*initial_bound
);
9123 // DEBUG: removed as unique ptr, so should auto-delete
9124 // delete initial_bound;
9126 return std::unique_ptr
<AST::ImplTraitTypeOneBound
> (
9127 new AST::ImplTraitTypeOneBound (std::move (value_bound
),
9131 // parse additional type param bounds
9132 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
9133 bounds
.push_back (std::move (initial_bound
));
9134 while (t
->get_id () == PLUS
)
9136 lexer
.skip_token ();
9138 // parse bound if it exists
9139 std::unique_ptr
<AST::TypeParamBound
> bound
9140 = parse_type_param_bound ();
9141 if (bound
== nullptr)
9143 // not an error as trailing plus may exist
9146 bounds
.push_back (std::move (bound
));
9148 t
= lexer
.peek_token ();
9151 return std::unique_ptr
<AST::ImplTraitType
> (
9152 new AST::ImplTraitType (std::move (bounds
), locus
));
9155 case QUESTION_MARK
: {
9156 // either TraitObjectType or TraitObjectTypeOneBound
9157 bool has_dyn
= false;
9158 if (t
->get_id () == DYN
)
9160 lexer
.skip_token ();
9164 if (lexer
.peek_token ()->get_id () == LIFETIME
)
9166 /* cannot be one bound because lifetime prevents it from being
9168 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
9169 = parse_type_param_bounds ();
9171 return std::unique_ptr
<AST::TraitObjectType
> (
9172 new AST::TraitObjectType (std::move (bounds
), t
->get_locus (),
9177 // should be trait bound, so parse trait bound
9178 std::unique_ptr
<AST::TraitBound
> initial_bound
9179 = parse_trait_bound ();
9180 if (initial_bound
== nullptr)
9185 lexer
.peek_token ()->get_locus (),
9186 "failed to parse TraitObjectType initial bound");
9187 add_error (std::move (error
));
9193 // short cut if next token isn't '+'
9194 t
= lexer
.peek_token ();
9195 if (t
->get_id () != PLUS
)
9197 // convert trait bound to value object
9198 AST::TraitBound
value_bound (*initial_bound
);
9200 // DEBUG: removed as unique ptr, so should auto delete
9201 // delete initial_bound;
9203 return std::unique_ptr
<AST::TraitObjectTypeOneBound
> (
9204 new AST::TraitObjectTypeOneBound (std::move (value_bound
),
9205 t
->get_locus (), has_dyn
));
9208 // parse additional type param bounds
9209 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
9210 bounds
.push_back (std::move (initial_bound
));
9211 while (t
->get_id () == PLUS
)
9213 lexer
.skip_token ();
9215 // parse bound if it exists
9216 std::unique_ptr
<AST::TypeParamBound
> bound
9217 = parse_type_param_bound ();
9218 if (bound
== nullptr)
9220 // not an error as trailing plus may exist
9223 bounds
.push_back (std::move (bound
));
9225 t
= lexer
.peek_token ();
9228 return std::unique_ptr
<AST::TraitObjectType
> (
9229 new AST::TraitObjectType (std::move (bounds
), t
->get_locus (),
9235 add_error (Error (t
->get_locus (), "unrecognised token %qs in type",
9236 t
->get_token_description ()));
9242 /* Parses a type that has '(' as its first character. Returns a tuple type,
9243 * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
9244 * on following characters. */
9245 template <typename ManagedTokenSource
>
9246 std::unique_ptr
<AST::Type
>
9247 Parser
<ManagedTokenSource
>::parse_paren_prefixed_type ()
9249 /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
9250 * a trait bound, not a parenthesised type, so that it can still be used in
9251 * type param bounds. */
9253 /* NOTE: this implementation is really shit but I couldn't think of a better
9254 * one. It requires essentially breaking polymorphism and downcasting via
9255 * virtual method abuse, as it was copied from the rustc implementation (in
9256 * which types are reified due to tagged union), after a more OOP attempt by
9258 location_t left_delim_locus
= lexer
.peek_token ()->get_locus ();
9261 lexer
.skip_token ();
9262 /* while next token isn't close delim, parse comma-separated types, saving
9263 * whether trailing comma happens */
9264 const_TokenPtr t
= lexer
.peek_token ();
9265 bool trailing_comma
= true;
9266 std::vector
<std::unique_ptr
<AST::Type
>> types
;
9268 while (t
->get_id () != RIGHT_PAREN
)
9270 std::unique_ptr
<AST::Type
> type
= parse_type ();
9271 if (type
== nullptr)
9273 Error
error (t
->get_locus (),
9274 "failed to parse type inside parentheses (probably "
9275 "tuple or parenthesised)");
9276 add_error (std::move (error
));
9280 types
.push_back (std::move (type
));
9282 t
= lexer
.peek_token ();
9283 if (t
->get_id () != COMMA
)
9285 trailing_comma
= false;
9288 lexer
.skip_token ();
9290 t
= lexer
.peek_token ();
9293 if (!skip_token (RIGHT_PAREN
))
9298 // if only one type and no trailing comma, then not a tuple type
9299 if (types
.size () == 1 && !trailing_comma
)
9301 // must be a TraitObjectType (with more than one bound)
9302 if (lexer
.peek_token ()->get_id () == PLUS
)
9304 // create type param bounds vector
9305 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
9307 // HACK: convert type to traitbound and add to bounds
9308 std::unique_ptr
<AST::Type
> released_ptr
= std::move (types
[0]);
9309 std::unique_ptr
<AST::TraitBound
> converted_bound (
9310 released_ptr
->to_trait_bound (true));
9311 if (converted_bound
== nullptr)
9314 lexer
.peek_token ()->get_locus (),
9315 "failed to hackily converted parsed type to trait bound");
9316 add_error (std::move (error
));
9320 bounds
.push_back (std::move (converted_bound
));
9322 t
= lexer
.peek_token ();
9323 while (t
->get_id () == PLUS
)
9325 lexer
.skip_token ();
9327 // attempt to parse typeparambound
9328 std::unique_ptr
<AST::TypeParamBound
> bound
9329 = parse_type_param_bound ();
9330 if (bound
== nullptr)
9332 // not an error if null
9335 bounds
.push_back (std::move (bound
));
9337 t
= lexer
.peek_token ();
9340 return std::unique_ptr
<AST::TraitObjectType
> (
9341 new AST::TraitObjectType (std::move (bounds
), left_delim_locus
,
9346 // release vector pointer
9347 std::unique_ptr
<AST::Type
> released_ptr
= std::move (types
[0]);
9348 /* HACK: attempt to convert to trait bound. if fails, parenthesised
9350 std::unique_ptr
<AST::TraitBound
> converted_bound (
9351 released_ptr
->to_trait_bound (true));
9352 if (converted_bound
== nullptr)
9354 // parenthesised type
9355 return std::unique_ptr
<AST::ParenthesisedType
> (
9356 new AST::ParenthesisedType (std::move (released_ptr
),
9361 // trait object type (one bound)
9363 // get value semantics trait bound
9364 AST::TraitBound
value_bound (*converted_bound
);
9366 return std::unique_ptr
<AST::TraitObjectTypeOneBound
> (
9367 new AST::TraitObjectTypeOneBound (value_bound
,
9374 return std::unique_ptr
<AST::TupleType
> (
9375 new AST::TupleType (std::move (types
), left_delim_locus
));
9377 /* TODO: ensure that this ensures that dynamic dispatch for traits is not
9381 /* Parses a type that has 'for' as its first character. This means it has a
9382 * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
9383 * TraitObjectTypeOneBound depending on following characters. */
9384 template <typename ManagedTokenSource
>
9385 std::unique_ptr
<AST::Type
>
9386 Parser
<ManagedTokenSource
>::parse_for_prefixed_type ()
9388 location_t for_locus
= lexer
.peek_token ()->get_locus ();
9389 // parse for lifetimes in type
9390 std::vector
<AST::LifetimeParam
> for_lifetimes
= parse_for_lifetimes ();
9392 // branch on next token - either function or a trait type
9393 const_TokenPtr t
= lexer
.peek_token ();
9394 switch (t
->get_id ())
9401 return parse_bare_function_type (std::move (for_lifetimes
));
9402 case SCOPE_RESOLUTION
:
9409 // path, so trait type
9411 // parse type path to finish parsing trait bound
9412 AST::TypePath path
= parse_type_path ();
9414 t
= lexer
.peek_token ();
9415 if (t
->get_id () != PLUS
)
9417 // must be one-bound trait type
9418 // create trait bound value object
9419 AST::TraitBound
bound (std::move (path
), for_locus
, false, false,
9420 std::move (for_lifetimes
));
9422 return std::unique_ptr
<AST::TraitObjectTypeOneBound
> (
9423 new AST::TraitObjectTypeOneBound (std::move (bound
), for_locus
));
9426 /* more than one bound trait type (or at least parsed as it - could be
9427 * trailing '+') create trait bound pointer and bounds */
9428 std::unique_ptr
<AST::TraitBound
> initial_bound (
9429 new AST::TraitBound (std::move (path
), for_locus
, false, false,
9430 std::move (for_lifetimes
)));
9431 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
9432 bounds
.push_back (std::move (initial_bound
));
9434 while (t
->get_id () == PLUS
)
9436 lexer
.skip_token ();
9438 // parse type param bound if it exists
9439 std::unique_ptr
<AST::TypeParamBound
> bound
9440 = parse_type_param_bound ();
9441 if (bound
== nullptr)
9443 // not an error - e.g. trailing plus
9446 bounds
.push_back (std::move (bound
));
9448 t
= lexer
.peek_token ();
9451 return std::unique_ptr
<AST::TraitObjectType
> (
9452 new AST::TraitObjectType (std::move (bounds
), for_locus
, false));
9456 add_error (Error (t
->get_locus (),
9457 "unrecognised token %qs in bare function type or trait "
9458 "object type or trait object type one bound",
9459 t
->get_token_description ()));
9465 // Parses a maybe named param used in bare function types.
9466 template <typename ManagedTokenSource
>
9467 AST::MaybeNamedParam
9468 Parser
<ManagedTokenSource
>::parse_maybe_named_param (AST::AttrVec outer_attrs
)
9470 /* Basically guess that param is named if first token is identifier or
9471 * underscore and second token is semicolon. This should probably have no
9472 * exceptions. rustc uses backtracking to parse these, but at the time of
9473 * writing gccrs has no backtracking capabilities. */
9474 const_TokenPtr current
= lexer
.peek_token ();
9475 const_TokenPtr next
= lexer
.peek_token (1);
9478 AST::MaybeNamedParam::ParamKind kind
= AST::MaybeNamedParam::UNNAMED
;
9480 if (current
->get_id () == IDENTIFIER
&& next
->get_id () == COLON
)
9484 kind
= AST::MaybeNamedParam::IDENTIFIER
;
9485 lexer
.skip_token (1);
9487 else if (current
->get_id () == UNDERSCORE
&& next
->get_id () == COLON
)
9490 name
= {Values::Keywords::UNDERSCORE
, current
->get_locus ()};
9491 kind
= AST::MaybeNamedParam::WILDCARD
;
9492 lexer
.skip_token (1);
9495 // parse type (required)
9496 std::unique_ptr
<AST::Type
> type
= parse_type ();
9497 if (type
== nullptr)
9499 Error
error (lexer
.peek_token ()->get_locus (),
9500 "failed to parse type in maybe named param");
9501 add_error (std::move (error
));
9503 return AST::MaybeNamedParam::create_error ();
9506 return AST::MaybeNamedParam (std::move (name
), kind
, std::move (type
),
9507 std::move (outer_attrs
), current
->get_locus ());
9510 /* Parses a bare function type (with the given for lifetimes for convenience -
9511 * does not parse them itself). */
9512 template <typename ManagedTokenSource
>
9513 std::unique_ptr
<AST::BareFunctionType
>
9514 Parser
<ManagedTokenSource
>::parse_bare_function_type (
9515 std::vector
<AST::LifetimeParam
> for_lifetimes
)
9517 // TODO: pass in for lifetime location as param
9518 location_t best_try_locus
= lexer
.peek_token ()->get_locus ();
9520 AST::FunctionQualifiers qualifiers
= parse_function_qualifiers ();
9522 if (!skip_token (FN_KW
))
9525 if (!skip_token (LEFT_PAREN
))
9528 // parse function params, if they exist
9529 std::vector
<AST::MaybeNamedParam
> params
;
9530 bool is_variadic
= false;
9531 AST::AttrVec variadic_attrs
;
9533 const_TokenPtr t
= lexer
.peek_token ();
9534 while (t
->get_id () != RIGHT_PAREN
)
9536 AST::AttrVec temp_attrs
= parse_outer_attributes ();
9538 if (lexer
.peek_token ()->get_id () == ELLIPSIS
)
9540 lexer
.skip_token ();
9542 variadic_attrs
= std::move (temp_attrs
);
9544 t
= lexer
.peek_token ();
9546 if (t
->get_id () != RIGHT_PAREN
)
9548 Error
error (t
->get_locus (),
9549 "expected right parentheses after variadic in maybe "
9551 "parameters, found %qs",
9552 t
->get_token_description ());
9553 add_error (std::move (error
));
9561 AST::MaybeNamedParam param
9562 = parse_maybe_named_param (std::move (temp_attrs
));
9563 if (param
.is_error ())
9566 lexer
.peek_token ()->get_locus (),
9567 "failed to parse maybe named param in bare function type");
9568 add_error (std::move (error
));
9572 params
.push_back (std::move (param
));
9574 if (lexer
.peek_token ()->get_id () != COMMA
)
9577 lexer
.skip_token ();
9578 t
= lexer
.peek_token ();
9581 if (!skip_token (RIGHT_PAREN
))
9584 // bare function return type, if exists
9585 std::unique_ptr
<AST::TypeNoBounds
> return_type
= nullptr;
9586 if (lexer
.peek_token ()->get_id () == RETURN_TYPE
)
9588 lexer
.skip_token ();
9590 // parse required TypeNoBounds
9591 return_type
= parse_type_no_bounds ();
9592 if (return_type
== nullptr)
9594 Error
error (lexer
.peek_token ()->get_locus (),
9595 "failed to parse return type (type no bounds) in bare "
9597 add_error (std::move (error
));
9603 return std::unique_ptr
<AST::BareFunctionType
> (
9604 new AST::BareFunctionType (std::move (for_lifetimes
),
9605 std::move (qualifiers
), std::move (params
),
9606 is_variadic
, std::move (variadic_attrs
),
9607 std::move (return_type
), best_try_locus
));
9610 template <typename ManagedTokenSource
>
9611 std::unique_ptr
<AST::ReferenceType
>
9612 Parser
<ManagedTokenSource
>::parse_reference_type_inner (location_t locus
)
9614 // parse optional lifetime
9615 AST::Lifetime lifetime
= AST::Lifetime::elided ();
9616 if (lexer
.peek_token ()->get_id () == LIFETIME
)
9618 auto parsed_lifetime
= parse_lifetime (true);
9619 if (parsed_lifetime
)
9621 lifetime
= parsed_lifetime
.value ();
9625 Error
error (lexer
.peek_token ()->get_locus (),
9626 "failed to parse lifetime in reference type");
9627 add_error (std::move (error
));
9633 bool is_mut
= false;
9634 if (lexer
.peek_token ()->get_id () == MUT
)
9636 lexer
.skip_token ();
9640 // parse type no bounds, which is required
9641 std::unique_ptr
<AST::TypeNoBounds
> type
= parse_type_no_bounds ();
9642 if (type
== nullptr)
9644 Error
error (lexer
.peek_token ()->get_locus (),
9645 "failed to parse referenced type in reference type");
9646 add_error (std::move (error
));
9651 return std::unique_ptr
<AST::ReferenceType
> (
9652 new AST::ReferenceType (is_mut
, std::move (type
), locus
,
9653 std::move (lifetime
)));
9656 // Parses a reference type (mutable or immutable, with given lifetime).
9657 template <typename ManagedTokenSource
>
9658 std::unique_ptr
<AST::ReferenceType
>
9659 Parser
<ManagedTokenSource
>::parse_reference_type ()
9661 auto t
= lexer
.peek_token ();
9662 auto locus
= t
->get_locus ();
9664 switch (t
->get_id ())
9668 return parse_reference_type_inner (locus
);
9670 skip_token (LOGICAL_AND
);
9671 return std::unique_ptr
<AST::ReferenceType
> (
9672 new AST::ReferenceType (false, parse_reference_type_inner (locus
),
9675 rust_unreachable ();
9679 // Parses a raw (unsafe) pointer type.
9680 template <typename ManagedTokenSource
>
9681 std::unique_ptr
<AST::RawPointerType
>
9682 Parser
<ManagedTokenSource
>::parse_raw_pointer_type ()
9684 location_t locus
= lexer
.peek_token ()->get_locus ();
9685 skip_token (ASTERISK
);
9687 AST::RawPointerType::PointerType kind
= AST::RawPointerType::CONST
;
9689 // branch on next token for pointer kind info
9690 const_TokenPtr t
= lexer
.peek_token ();
9691 switch (t
->get_id ())
9694 kind
= AST::RawPointerType::MUT
;
9695 lexer
.skip_token ();
9698 kind
= AST::RawPointerType::CONST
;
9699 lexer
.skip_token ();
9702 add_error (Error (t
->get_locus (),
9703 "unrecognised token %qs in raw pointer type",
9704 t
->get_token_description ()));
9709 // parse type no bounds (required)
9710 std::unique_ptr
<AST::TypeNoBounds
> type
= parse_type_no_bounds ();
9711 if (type
== nullptr)
9713 Error
error (lexer
.peek_token ()->get_locus (),
9714 "failed to parse pointed type of raw pointer type");
9715 add_error (std::move (error
));
9720 return std::unique_ptr
<AST::RawPointerType
> (
9721 new AST::RawPointerType (kind
, std::move (type
), locus
));
9724 /* Parses a slice or array type, depending on following arguments (as
9725 * lookahead is not possible). */
9726 template <typename ManagedTokenSource
>
9727 std::unique_ptr
<AST::TypeNoBounds
>
9728 Parser
<ManagedTokenSource
>::parse_slice_or_array_type ()
9730 location_t locus
= lexer
.peek_token ()->get_locus ();
9731 skip_token (LEFT_SQUARE
);
9733 // parse inner type (required)
9734 std::unique_ptr
<AST::Type
> inner_type
= parse_type ();
9735 if (inner_type
== nullptr)
9737 Error
error (lexer
.peek_token ()->get_locus (),
9738 "failed to parse inner type in slice or array type");
9739 add_error (std::move (error
));
9744 // branch on next token
9745 const_TokenPtr t
= lexer
.peek_token ();
9746 switch (t
->get_id ())
9750 lexer
.skip_token ();
9752 return std::unique_ptr
<AST::SliceType
> (
9753 new AST::SliceType (std::move (inner_type
), locus
));
9756 lexer
.skip_token ();
9758 // parse required array size expression
9759 std::unique_ptr
<AST::Expr
> size
= parse_expr ();
9760 if (size
== nullptr)
9762 Error
error (lexer
.peek_token ()->get_locus (),
9763 "failed to parse size expression in array type");
9764 add_error (std::move (error
));
9769 if (!skip_token (RIGHT_SQUARE
))
9774 return std::unique_ptr
<AST::ArrayType
> (
9775 new AST::ArrayType (std::move (inner_type
), std::move (size
), locus
));
9780 Error (t
->get_locus (),
9781 "unrecognised token %qs in slice or array type after inner type",
9782 t
->get_token_description ()));
9788 // Parses a type, taking into account type boundary disambiguation.
9789 template <typename ManagedTokenSource
>
9790 std::unique_ptr
<AST::TypeNoBounds
>
9791 Parser
<ManagedTokenSource
>::parse_type_no_bounds ()
9793 const_TokenPtr t
= lexer
.peek_token ();
9794 switch (t
->get_id ())
9797 // never type - can't be macro as no path beforehand
9798 lexer
.skip_token ();
9799 return std::unique_ptr
<AST::NeverType
> (
9800 new AST::NeverType (t
->get_locus ()));
9802 // slice type or array type - requires further disambiguation
9803 return parse_slice_or_array_type ();
9806 // qualified path in type
9807 AST::QualifiedPathInType path
= parse_qualified_path_in_type ();
9808 if (path
.is_error ())
9810 Error
error (t
->get_locus (),
9811 "failed to parse qualified path in type");
9812 add_error (std::move (error
));
9816 return std::unique_ptr
<AST::QualifiedPathInType
> (
9817 new AST::QualifiedPathInType (std::move (path
)));
9821 lexer
.skip_token ();
9822 return std::unique_ptr
<AST::InferredType
> (
9823 new AST::InferredType (t
->get_locus ()));
9826 return parse_raw_pointer_type ();
9827 case AMP
: // does this also include AMP_AMP? Yes! Which is... LOGICAL_AND?
9830 return parse_reference_type ();
9832 /* probably a lifetime bound, so probably type param bounds in
9833 * TraitObjectType. this is not allowed, but detection here for error
9835 add_error (Error (t
->get_locus (),
9836 "lifetime bounds (i.e. in type param bounds, in "
9837 "TraitObjectType) are not allowed as TypeNoBounds"));
9846 case SCOPE_RESOLUTION
: {
9847 // macro invocation or type path - requires further disambiguation.
9848 /* for parsing path component of each rule, perhaps parse it as a
9849 * typepath and attempt conversion to simplepath if a trailing '!' is
9851 /* Type path also includes TraitObjectTypeOneBound BUT if it starts
9852 * with it, it is exactly the same as a TypePath syntactically, so
9853 * this is a syntactical ambiguity. As such, the parser will parse it
9854 * as a TypePath. This, however, does not prevent TraitObjectType from
9855 * starting with a typepath. */
9857 // parse path as type path
9858 AST::TypePath path
= parse_type_path ();
9859 if (path
.is_error ())
9863 "failed to parse path as first component of type no bounds");
9864 add_error (std::move (error
));
9868 location_t locus
= path
.get_locus ();
9870 // branch on next token
9871 t
= lexer
.peek_token ();
9872 switch (t
->get_id ())
9876 // convert to simple path
9877 AST::SimplePath macro_path
= path
.as_simple_path ();
9878 if (macro_path
.is_empty ())
9880 Error
error (t
->get_locus (),
9881 "failed to parse simple path in macro "
9882 "invocation (for type)");
9883 add_error (std::move (error
));
9888 lexer
.skip_token ();
9890 AST::DelimTokenTree tok_tree
= parse_delim_token_tree ();
9892 return AST::MacroInvocation::Regular (
9893 AST::MacroInvocData (std::move (macro_path
),
9894 std::move (tok_tree
)),
9898 // assume that this is a type path and not an error
9899 return std::unique_ptr
<AST::TypePath
> (
9900 new AST::TypePath (std::move (path
)));
9904 /* tuple type or parenthesised type - requires further disambiguation
9905 * (the usual). ok apparently can be a parenthesised TraitBound too, so
9906 * could be TraitObjectTypeOneBound */
9907 return parse_paren_prefixed_type_no_bounds ();
9914 // bare function type (with no for lifetimes)
9915 return parse_bare_function_type (std::vector
<AST::LifetimeParam
> ());
9917 lexer
.skip_token ();
9918 if (lexer
.peek_token ()->get_id () == LIFETIME
)
9920 /* cannot be one bound because lifetime prevents it from being
9921 * traitbound not allowed as type no bounds, only here for error
9924 lexer
.peek_token ()->get_locus (),
9925 "lifetime (probably lifetime bound, in type param "
9926 "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
9927 add_error (std::move (error
));
9933 // should be trait bound, so parse trait bound
9934 std::unique_ptr
<AST::TraitBound
> initial_bound
= parse_trait_bound ();
9935 if (initial_bound
== nullptr)
9937 Error
error (lexer
.peek_token ()->get_locus (),
9938 "failed to parse ImplTraitTypeOneBound bound");
9939 add_error (std::move (error
));
9944 location_t locus
= t
->get_locus ();
9946 // ensure not a trait with multiple bounds
9947 t
= lexer
.peek_token ();
9948 if (t
->get_id () == PLUS
)
9950 Error
error (t
->get_locus (),
9951 "plus after trait bound means an ImplTraitType, "
9952 "which is not allowed as a TypeNoBounds");
9953 add_error (std::move (error
));
9958 // convert trait bound to value object
9959 AST::TraitBound
value_bound (*initial_bound
);
9961 return std::unique_ptr
<AST::ImplTraitTypeOneBound
> (
9962 new AST::ImplTraitTypeOneBound (std::move (value_bound
), locus
));
9965 case QUESTION_MARK
: {
9966 // either TraitObjectTypeOneBound
9967 bool has_dyn
= false;
9968 if (t
->get_id () == DYN
)
9970 lexer
.skip_token ();
9974 if (lexer
.peek_token ()->get_id () == LIFETIME
)
9976 /* means that cannot be TraitObjectTypeOneBound - so here for
9978 Error
error (lexer
.peek_token ()->get_locus (),
9979 "lifetime as bound in TraitObjectTypeOneBound "
9980 "is not allowed, so cannot be TypeNoBounds");
9981 add_error (std::move (error
));
9986 // should be trait bound, so parse trait bound
9987 std::unique_ptr
<AST::TraitBound
> initial_bound
= parse_trait_bound ();
9988 if (initial_bound
== nullptr)
9991 lexer
.peek_token ()->get_locus (),
9992 "failed to parse TraitObjectTypeOneBound initial bound");
9993 add_error (std::move (error
));
9998 location_t locus
= t
->get_locus ();
10000 // detect error with plus as next token
10001 t
= lexer
.peek_token ();
10002 if (t
->get_id () == PLUS
)
10004 Error
error (t
->get_locus (),
10005 "plus after trait bound means a TraitObjectType, "
10006 "which is not allowed as a TypeNoBounds");
10007 add_error (std::move (error
));
10012 // convert trait bound to value object
10013 AST::TraitBound
value_bound (*initial_bound
);
10015 return std::unique_ptr
<AST::TraitObjectTypeOneBound
> (
10016 new AST::TraitObjectTypeOneBound (std::move (value_bound
), locus
,
10020 add_error (Error (t
->get_locus (),
10021 "unrecognised token %qs in type no bounds",
10022 t
->get_token_description ()));
10028 // Parses a type no bounds beginning with '('.
10029 template <typename ManagedTokenSource
>
10030 std::unique_ptr
<AST::TypeNoBounds
>
10031 Parser
<ManagedTokenSource
>::parse_paren_prefixed_type_no_bounds ()
10033 /* NOTE: this could probably be parsed without the HACK solution of
10034 * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
10036 /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
10037 * considered a trait bound, not a parenthesised type, so that it can still
10038 * be used in type param bounds. */
10040 location_t left_paren_locus
= lexer
.peek_token ()->get_locus ();
10043 lexer
.skip_token ();
10044 /* while next token isn't close delim, parse comma-separated types, saving
10045 * whether trailing comma happens */
10046 const_TokenPtr t
= lexer
.peek_token ();
10047 bool trailing_comma
= true;
10048 std::vector
<std::unique_ptr
<AST::Type
>> types
;
10050 while (t
->get_id () != RIGHT_PAREN
)
10052 std::unique_ptr
<AST::Type
> type
= parse_type ();
10053 if (type
== nullptr)
10055 Error
error (t
->get_locus (),
10056 "failed to parse type inside parentheses (probably "
10057 "tuple or parenthesised)");
10058 add_error (std::move (error
));
10062 types
.push_back (std::move (type
));
10064 t
= lexer
.peek_token ();
10065 if (t
->get_id () != COMMA
)
10067 trailing_comma
= false;
10070 lexer
.skip_token ();
10072 t
= lexer
.peek_token ();
10075 if (!skip_token (RIGHT_PAREN
))
10080 // if only one type and no trailing comma, then not a tuple type
10081 if (types
.size () == 1 && !trailing_comma
)
10083 // must be a TraitObjectType (with more than one bound)
10084 if (lexer
.peek_token ()->get_id () == PLUS
)
10086 // error - this is not allowed for type no bounds
10087 Error
error (lexer
.peek_token ()->get_locus (),
10088 "plus (implying TraitObjectType as type param "
10089 "bounds) is not allowed in type no bounds");
10090 add_error (std::move (error
));
10096 // release vector pointer
10097 std::unique_ptr
<AST::Type
> released_ptr
= std::move (types
[0]);
10098 /* HACK: attempt to convert to trait bound. if fails, parenthesised
10100 std::unique_ptr
<AST::TraitBound
> converted_bound (
10101 released_ptr
->to_trait_bound (true));
10102 if (converted_bound
== nullptr)
10104 // parenthesised type
10105 return std::unique_ptr
<AST::ParenthesisedType
> (
10106 new AST::ParenthesisedType (std::move (released_ptr
),
10107 left_paren_locus
));
10111 // trait object type (one bound)
10113 // get value semantics trait bound
10114 AST::TraitBound
value_bound (*converted_bound
);
10116 return std::unique_ptr
<AST::TraitObjectTypeOneBound
> (
10117 new AST::TraitObjectTypeOneBound (value_bound
,
10118 left_paren_locus
));
10124 return std::unique_ptr
<AST::TupleType
> (
10125 new AST::TupleType (std::move (types
), left_paren_locus
));
10127 /* TODO: ensure that this ensures that dynamic dispatch for traits is not
10131 /* Parses a literal pattern or range pattern. Assumes that literals passed in
10132 * are valid range pattern bounds. Do not pass in paths in expressions, for
10134 template <typename ManagedTokenSource
>
10135 std::unique_ptr
<AST::Pattern
>
10136 Parser
<ManagedTokenSource
>::parse_literal_or_range_pattern ()
10138 const_TokenPtr range_lower
= lexer
.peek_token ();
10139 AST::Literal::LitType type
= AST::Literal::STRING
;
10140 bool has_minus
= false;
10143 switch (range_lower
->get_id ())
10146 type
= AST::Literal::CHAR
;
10147 lexer
.skip_token ();
10149 case BYTE_CHAR_LITERAL
:
10150 type
= AST::Literal::BYTE
;
10151 lexer
.skip_token ();
10154 type
= AST::Literal::INT
;
10155 lexer
.skip_token ();
10157 case FLOAT_LITERAL
:
10158 type
= AST::Literal::FLOAT
;
10159 lexer
.skip_token ();
10162 // branch on next token
10163 range_lower
= lexer
.peek_token (1);
10164 switch (range_lower
->get_id ())
10167 type
= AST::Literal::INT
;
10169 lexer
.skip_token (1);
10171 case FLOAT_LITERAL
:
10172 type
= AST::Literal::FLOAT
;
10174 lexer
.skip_token (1);
10177 add_error (Error (range_lower
->get_locus (),
10178 "token type %qs cannot be parsed as range pattern "
10179 "bound or literal after minus symbol",
10180 range_lower
->get_token_description ()));
10187 Error (range_lower
->get_locus (),
10188 "token type %qs cannot be parsed as range pattern bound",
10189 range_lower
->get_token_description ()));
10194 const_TokenPtr next
= lexer
.peek_token ();
10195 if (next
->get_id () == DOT_DOT_EQ
|| next
->get_id () == ELLIPSIS
10196 || next
->get_id () == DOT_DOT
)
10198 AST::RangeKind kind
= AST::tokenid_to_rangekind (next
->get_id ());
10200 lexer
.skip_token ();
10201 std::unique_ptr
<AST::RangePatternBound
> lower (
10202 new AST::RangePatternBoundLiteral (
10203 AST::Literal (range_lower
->get_str (), type
,
10204 PrimitiveCoreType::CORETYPE_UNKNOWN
),
10205 range_lower
->get_locus (), has_minus
));
10207 std::unique_ptr
<AST::RangePatternBound
> upper
10208 = parse_range_pattern_bound ();
10209 if (upper
== nullptr)
10211 Error
error (next
->get_locus (),
10212 "failed to parse range pattern bound in range pattern");
10213 add_error (std::move (error
));
10218 return std::unique_ptr
<AST::RangePattern
> (
10219 new AST::RangePattern (std::move (lower
), std::move (upper
), kind
,
10220 range_lower
->get_locus ()));
10225 return std::unique_ptr
<AST::LiteralPattern
> (
10226 new AST::LiteralPattern (range_lower
->get_str (), type
,
10227 range_lower
->get_locus (),
10228 range_lower
->get_type_hint ()));
10232 // Parses a range pattern bound (value only).
10233 template <typename ManagedTokenSource
>
10234 std::unique_ptr
<AST::RangePatternBound
>
10235 Parser
<ManagedTokenSource
>::parse_range_pattern_bound ()
10237 const_TokenPtr range_lower
= lexer
.peek_token ();
10238 location_t range_lower_locus
= range_lower
->get_locus ();
10241 switch (range_lower
->get_id ())
10244 lexer
.skip_token ();
10245 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10246 new AST::RangePatternBoundLiteral (
10247 AST::Literal (range_lower
->get_str (), AST::Literal::CHAR
,
10248 range_lower
->get_type_hint ()),
10249 range_lower_locus
));
10250 case BYTE_CHAR_LITERAL
:
10251 lexer
.skip_token ();
10252 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10253 new AST::RangePatternBoundLiteral (
10254 AST::Literal (range_lower
->get_str (), AST::Literal::BYTE
,
10255 range_lower
->get_type_hint ()),
10256 range_lower_locus
));
10258 lexer
.skip_token ();
10259 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10260 new AST::RangePatternBoundLiteral (
10261 AST::Literal (range_lower
->get_str (), AST::Literal::INT
,
10262 range_lower
->get_type_hint ()),
10263 range_lower_locus
));
10264 case FLOAT_LITERAL
:
10265 lexer
.skip_token ();
10266 rust_debug ("warning: used deprecated float range pattern bound");
10267 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10268 new AST::RangePatternBoundLiteral (
10269 AST::Literal (range_lower
->get_str (), AST::Literal::FLOAT
,
10270 range_lower
->get_type_hint ()),
10271 range_lower_locus
));
10273 // branch on next token
10274 range_lower
= lexer
.peek_token (1);
10275 switch (range_lower
->get_id ())
10278 lexer
.skip_token (1);
10279 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10280 new AST::RangePatternBoundLiteral (
10281 AST::Literal (range_lower
->get_str (), AST::Literal::INT
,
10282 range_lower
->get_type_hint ()),
10283 range_lower_locus
, true));
10284 case FLOAT_LITERAL
:
10285 lexer
.skip_token (1);
10286 rust_debug ("warning: used deprecated float range pattern bound");
10287 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10288 new AST::RangePatternBoundLiteral (
10289 AST::Literal (range_lower
->get_str (), AST::Literal::FLOAT
,
10290 range_lower
->get_type_hint ()),
10291 range_lower_locus
, true));
10293 add_error (Error (range_lower
->get_locus (),
10294 "token type %qs cannot be parsed as range pattern "
10295 "bound after minus symbol",
10296 range_lower
->get_token_description ()));
10305 case SCOPE_RESOLUTION
:
10306 case DOLLAR_SIGN
: {
10307 // path in expression
10308 AST::PathInExpression path
= parse_path_in_expression ();
10309 if (path
.is_error ())
10312 range_lower
->get_locus (),
10313 "failed to parse path in expression range pattern bound");
10314 add_error (std::move (error
));
10318 return std::unique_ptr
<AST::RangePatternBoundPath
> (
10319 new AST::RangePatternBoundPath (std::move (path
)));
10323 // qualified path in expression
10324 AST::QualifiedPathInExpression path
10325 = parse_qualified_path_in_expression ();
10326 if (path
.is_error ())
10328 Error
error (range_lower
->get_locus (),
10329 "failed to parse qualified path in expression range "
10331 add_error (std::move (error
));
10335 return std::unique_ptr
<AST::RangePatternBoundQualPath
> (
10336 new AST::RangePatternBoundQualPath (std::move (path
)));
10340 Error (range_lower
->get_locus (),
10341 "token type %qs cannot be parsed as range pattern bound",
10342 range_lower
->get_token_description ()));
10348 template <typename ManagedTokenSource
>
10349 std::unique_ptr
<AST::Pattern
>
10350 Parser
<ManagedTokenSource
>::parse_pattern ()
10352 location_t start_locus
= lexer
.peek_token ()->get_locus ();
10354 /* skip optional starting pipe */
10355 maybe_skip_token (PIPE
);
10357 auto first
= parse_pattern_no_alt ();
10359 if (lexer
.peek_token ()->get_id () != PIPE
)
10360 /* no alternates */
10363 std::vector
<std::unique_ptr
<AST::Pattern
>> alts
;
10364 alts
.push_back (std::move (first
));
10368 lexer
.skip_token ();
10369 alts
.push_back (parse_pattern_no_alt ());
10372 while (lexer
.peek_token ()->get_id () == PIPE
);
10375 return std::unique_ptr
<AST::Pattern
> (
10376 new AST::AltPattern (std::move (alts
), start_locus
));
10379 // Parses a pattern without alternates ('|')
10380 // (will further disambiguate any pattern).
10381 template <typename ManagedTokenSource
>
10382 std::unique_ptr
<AST::Pattern
>
10383 Parser
<ManagedTokenSource
>::parse_pattern_no_alt ()
10385 const_TokenPtr t
= lexer
.peek_token ();
10386 switch (t
->get_id ())
10389 lexer
.skip_token ();
10390 return std::unique_ptr
<AST::LiteralPattern
> (
10391 new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL
,
10392 AST::Literal::BOOL
, t
->get_locus (),
10393 t
->get_type_hint ()));
10394 case FALSE_LITERAL
:
10395 lexer
.skip_token ();
10396 return std::unique_ptr
<AST::LiteralPattern
> (
10397 new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL
,
10398 AST::Literal::BOOL
, t
->get_locus (),
10399 t
->get_type_hint ()));
10401 case BYTE_CHAR_LITERAL
:
10403 case FLOAT_LITERAL
:
10404 return parse_literal_or_range_pattern ();
10405 case STRING_LITERAL
:
10406 lexer
.skip_token ();
10407 return std::unique_ptr
<AST::LiteralPattern
> (
10408 new AST::LiteralPattern (t
->get_str (), AST::Literal::STRING
,
10409 t
->get_locus (), t
->get_type_hint ()));
10410 case BYTE_STRING_LITERAL
:
10411 lexer
.skip_token ();
10412 return std::unique_ptr
<AST::LiteralPattern
> (
10413 new AST::LiteralPattern (t
->get_str (), AST::Literal::BYTE_STRING
,
10414 t
->get_locus (), t
->get_type_hint ()));
10415 case RAW_STRING_LITERAL
:
10416 lexer
.skip_token ();
10417 return std::unique_ptr
<AST::LiteralPattern
> (
10418 new AST::LiteralPattern (t
->get_str (), AST::Literal::RAW_STRING
,
10419 t
->get_locus (), t
->get_type_hint ()));
10420 // raw string and raw byte string literals too if they are readded to
10423 if (lexer
.peek_token (1)->get_id () == INT_LITERAL
)
10425 return parse_literal_or_range_pattern ();
10427 else if (lexer
.peek_token (1)->get_id () == FLOAT_LITERAL
)
10429 return parse_literal_or_range_pattern ();
10433 Error
error (t
->get_locus (), "unexpected token %<-%> in pattern - "
10434 "did you forget an integer literal");
10435 add_error (std::move (error
));
10440 lexer
.skip_token ();
10441 return std::unique_ptr
<AST::WildcardPattern
> (
10442 new AST::WildcardPattern (t
->get_locus ()));
10444 lexer
.skip_token ();
10445 return std::unique_ptr
<AST::RestPattern
> (
10446 new AST::RestPattern (t
->get_locus ()));
10449 return parse_identifier_pattern ();
10451 /* if identifier with no scope resolution afterwards, identifier
10452 * pattern. if scope resolution afterwards, path pattern (or range
10453 * pattern or struct pattern or tuple struct pattern) or macro
10455 return parse_ident_leading_pattern ();
10458 // reference pattern
10459 return parse_reference_pattern ();
10461 // tuple pattern or grouped pattern
10462 return parse_grouped_or_tuple_pattern ();
10465 return parse_slice_pattern ();
10468 // qualified path in expression or qualified range pattern bound
10469 AST::QualifiedPathInExpression path
10470 = parse_qualified_path_in_expression ();
10472 if (lexer
.peek_token ()->get_id () == DOT_DOT_EQ
10473 || lexer
.peek_token ()->get_id () == ELLIPSIS
10474 || lexer
.peek_token ()->get_id () == DOT_DOT
)
10476 // qualified range pattern bound, so parse rest of range pattern
10477 AST::RangeKind kind
10478 = AST::tokenid_to_rangekind (lexer
.peek_token ()->get_id ());
10479 lexer
.skip_token ();
10481 std::unique_ptr
<AST::RangePatternBoundQualPath
> lower_bound (
10482 new AST::RangePatternBoundQualPath (std::move (path
)));
10483 std::unique_ptr
<AST::RangePatternBound
> upper_bound
10484 = parse_range_pattern_bound ();
10486 return std::unique_ptr
<AST::RangePattern
> (
10487 new AST::RangePattern (std::move (lower_bound
),
10488 std::move (upper_bound
), kind
,
10493 // just qualified path in expression
10494 return std::unique_ptr
<AST::QualifiedPathInExpression
> (
10495 new AST::QualifiedPathInExpression (std::move (path
)));
10502 case SCOPE_RESOLUTION
:
10503 case DOLLAR_SIGN
: {
10504 // path in expression or range pattern bound
10505 AST::PathInExpression path
= parse_path_in_expression ();
10507 const_TokenPtr next
= lexer
.peek_token ();
10508 switch (next
->get_id ())
10513 // qualified range pattern bound, so parse rest of range pattern
10514 AST::RangeKind kind
= AST::tokenid_to_rangekind (next
->get_id ());
10515 lexer
.skip_token ();
10517 std::unique_ptr
<AST::RangePatternBoundPath
> lower_bound (
10518 new AST::RangePatternBoundPath (std::move (path
)));
10519 std::unique_ptr
<AST::RangePatternBound
> upper_bound
10520 = parse_range_pattern_bound ();
10522 return std::unique_ptr
<AST::RangePattern
> (
10523 new AST::RangePattern (std::move (lower_bound
),
10524 std::move (upper_bound
), kind
,
10525 next
->get_locus ()));
10528 return parse_macro_invocation_partial (std::move (path
),
10532 lexer
.skip_token ();
10535 std::unique_ptr
<AST::TupleStructItems
> items
10536 = parse_tuple_struct_items ();
10537 if (items
== nullptr)
10539 Error
error (lexer
.peek_token ()->get_locus (),
10540 "failed to parse tuple struct items");
10541 add_error (std::move (error
));
10546 if (!skip_token (RIGHT_PAREN
))
10551 return std::unique_ptr
<AST::TupleStructPattern
> (
10552 new AST::TupleStructPattern (std::move (path
),
10553 std::move (items
)));
10557 lexer
.skip_token ();
10559 // parse elements (optional)
10560 AST::StructPatternElements elems
= parse_struct_pattern_elems ();
10562 if (!skip_token (RIGHT_CURLY
))
10567 return std::unique_ptr
<AST::StructPattern
> (
10568 new AST::StructPattern (std::move (path
), t
->get_locus (),
10569 std::move (elems
)));
10572 // assume path in expression
10573 return std::unique_ptr
<AST::PathInExpression
> (
10574 new AST::PathInExpression (std::move (path
)));
10578 add_error (Error (t
->get_locus (), "unexpected token %qs in pattern",
10579 t
->get_token_description ()));
10585 // Parses a single or double reference pattern.
10586 template <typename ManagedTokenSource
>
10587 std::unique_ptr
<AST::ReferencePattern
>
10588 Parser
<ManagedTokenSource
>::parse_reference_pattern ()
10590 // parse double or single ref
10591 bool is_double_ref
= false;
10592 const_TokenPtr t
= lexer
.peek_token ();
10593 switch (t
->get_id ())
10597 lexer
.skip_token ();
10600 is_double_ref
= true;
10601 lexer
.skip_token ();
10604 add_error (Error (t
->get_locus (),
10605 "unexpected token %qs in reference pattern",
10606 t
->get_token_description ()));
10611 // parse mut (if it exists)
10612 bool is_mut
= false;
10613 if (lexer
.peek_token ()->get_id () == MUT
)
10616 lexer
.skip_token ();
10619 // parse pattern to get reference of (required)
10620 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern_no_alt ();
10621 if (pattern
== nullptr)
10623 Error
error (lexer
.peek_token ()->get_locus (),
10624 "failed to parse pattern in reference pattern");
10625 add_error (std::move (error
));
10631 return std::unique_ptr
<AST::ReferencePattern
> (
10632 new AST::ReferencePattern (std::move (pattern
), is_mut
, is_double_ref
,
10636 /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if
10637 * only a single element with no commas. */
10638 template <typename ManagedTokenSource
>
10639 std::unique_ptr
<AST::Pattern
>
10640 Parser
<ManagedTokenSource
>::parse_grouped_or_tuple_pattern ()
10642 location_t paren_locus
= lexer
.peek_token ()->get_locus ();
10643 skip_token (LEFT_PAREN
);
10645 // detect '..' token (ranged with no lower range)
10646 if (lexer
.peek_token ()->get_id () == DOT_DOT
)
10648 lexer
.skip_token ();
10650 // parse new patterns while next token is a comma
10651 std::vector
<std::unique_ptr
<AST::Pattern
>> patterns
;
10653 const_TokenPtr t
= lexer
.peek_token ();
10654 while (t
->get_id () == COMMA
)
10656 lexer
.skip_token ();
10658 // break if next token is ')'
10659 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
10664 // parse pattern, which is required
10665 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
10666 if (pattern
== nullptr)
10669 lexer
.peek_token ()->get_locus (),
10670 "failed to parse pattern inside ranged tuple pattern");
10671 add_error (std::move (error
));
10676 patterns
.push_back (std::move (pattern
));
10678 t
= lexer
.peek_token ();
10681 if (!skip_token (RIGHT_PAREN
))
10687 // create ranged tuple pattern items with only upper items
10688 std::unique_ptr
<AST::TuplePatternItemsRanged
> items (
10689 new AST::TuplePatternItemsRanged (
10690 std::vector
<std::unique_ptr
<AST::Pattern
>> (), std::move (patterns
)));
10691 return std::unique_ptr
<AST::TuplePattern
> (
10692 new AST::TuplePattern (std::move (items
), paren_locus
));
10694 else if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
10696 skip_token (RIGHT_PAREN
);
10697 auto items
= std::unique_ptr
<AST::TuplePatternItemsMultiple
> (
10698 new AST::TuplePatternItemsMultiple (
10699 std::vector
<std::unique_ptr
<AST::Pattern
>> ()));
10700 return std::unique_ptr
<AST::TuplePattern
> (
10701 new AST::TuplePattern (std::move (items
), paren_locus
));
10704 // parse initial pattern (required)
10705 std::unique_ptr
<AST::Pattern
> initial_pattern
= parse_pattern ();
10706 if (initial_pattern
== nullptr)
10708 Error
error (lexer
.peek_token ()->get_locus (),
10709 "failed to parse pattern in grouped or tuple pattern");
10710 add_error (std::move (error
));
10715 // branch on whether next token is a comma or not
10716 const_TokenPtr t
= lexer
.peek_token ();
10717 switch (t
->get_id ())
10721 lexer
.skip_token ();
10723 return std::unique_ptr
<AST::GroupedPattern
> (
10724 new AST::GroupedPattern (std::move (initial_pattern
), paren_locus
));
10727 lexer
.skip_token ();
10729 // create vector of patterns
10730 std::vector
<std::unique_ptr
<AST::Pattern
>> patterns
;
10731 patterns
.push_back (std::move (initial_pattern
));
10733 t
= lexer
.peek_token ();
10734 while (t
->get_id () != RIGHT_PAREN
&& t
->get_id () != DOT_DOT
)
10736 // parse pattern (required)
10737 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
10738 if (pattern
== nullptr)
10740 Error
error (t
->get_locus (),
10741 "failed to parse pattern in tuple pattern");
10742 add_error (std::move (error
));
10746 patterns
.push_back (std::move (pattern
));
10748 if (lexer
.peek_token ()->get_id () != COMMA
)
10751 lexer
.skip_token ();
10752 t
= lexer
.peek_token ();
10755 t
= lexer
.peek_token ();
10756 if (t
->get_id () == RIGHT_PAREN
)
10758 // non-ranged tuple pattern
10759 lexer
.skip_token ();
10761 std::unique_ptr
<AST::TuplePatternItemsMultiple
> items (
10762 new AST::TuplePatternItemsMultiple (std::move (patterns
)));
10763 return std::unique_ptr
<AST::TuplePattern
> (
10764 new AST::TuplePattern (std::move (items
), paren_locus
));
10766 else if (t
->get_id () == DOT_DOT
)
10768 // ranged tuple pattern
10769 lexer
.skip_token ();
10771 // parse upper patterns
10772 std::vector
<std::unique_ptr
<AST::Pattern
>> upper_patterns
;
10773 t
= lexer
.peek_token ();
10774 while (t
->get_id () == COMMA
)
10776 lexer
.skip_token ();
10779 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
10782 // parse pattern (required)
10783 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
10784 if (pattern
== nullptr)
10786 Error
error (lexer
.peek_token ()->get_locus (),
10787 "failed to parse pattern in tuple pattern");
10788 add_error (std::move (error
));
10792 upper_patterns
.push_back (std::move (pattern
));
10794 t
= lexer
.peek_token ();
10797 if (!skip_token (RIGHT_PAREN
))
10802 std::unique_ptr
<AST::TuplePatternItemsRanged
> items (
10803 new AST::TuplePatternItemsRanged (std::move (patterns
),
10804 std::move (upper_patterns
)));
10805 return std::unique_ptr
<AST::TuplePattern
> (
10806 new AST::TuplePattern (std::move (items
), paren_locus
));
10810 // some kind of error
10811 Error
error (t
->get_locus (),
10812 "failed to parse tuple pattern (probably) or maybe "
10813 "grouped pattern");
10814 add_error (std::move (error
));
10821 add_error (Error (t
->get_locus (),
10822 "unrecognised token %qs in grouped or tuple pattern "
10823 "after first pattern",
10824 t
->get_token_description ()));
10830 /* Parses a slice pattern that can match arrays or slices. Parses the square
10832 template <typename ManagedTokenSource
>
10833 std::unique_ptr
<AST::SlicePattern
>
10834 Parser
<ManagedTokenSource
>::parse_slice_pattern ()
10836 location_t square_locus
= lexer
.peek_token ()->get_locus ();
10837 std::vector
<std::unique_ptr
<AST::Pattern
>> patterns
;
10838 skip_token (LEFT_SQUARE
);
10840 if (lexer
.peek_token ()->get_id () == RIGHT_SQUARE
)
10842 skip_token (RIGHT_SQUARE
);
10843 return std::unique_ptr
<AST::SlicePattern
> (
10844 new AST::SlicePattern (std::move (patterns
), square_locus
));
10847 // parse initial pattern (required)
10848 std::unique_ptr
<AST::Pattern
> initial_pattern
= parse_pattern ();
10849 if (initial_pattern
== nullptr)
10851 Error
error (lexer
.peek_token ()->get_locus (),
10852 "failed to parse initial pattern in slice pattern");
10853 add_error (std::move (error
));
10858 patterns
.push_back (std::move (initial_pattern
));
10860 const_TokenPtr t
= lexer
.peek_token ();
10861 while (t
->get_id () == COMMA
)
10863 lexer
.skip_token ();
10865 // break if end bracket
10866 if (lexer
.peek_token ()->get_id () == RIGHT_SQUARE
)
10869 // parse pattern (required)
10870 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
10871 if (pattern
== nullptr)
10873 Error
error (lexer
.peek_token ()->get_locus (),
10874 "failed to parse pattern in slice pattern");
10875 add_error (std::move (error
));
10879 patterns
.push_back (std::move (pattern
));
10881 t
= lexer
.peek_token ();
10884 if (!skip_token (RIGHT_SQUARE
))
10889 return std::unique_ptr
<AST::SlicePattern
> (
10890 new AST::SlicePattern (std::move (patterns
), square_locus
));
10893 /* Parses an identifier pattern (pattern that binds a value matched to a
10895 template <typename ManagedTokenSource
>
10896 std::unique_ptr
<AST::IdentifierPattern
>
10897 Parser
<ManagedTokenSource
>::parse_identifier_pattern ()
10899 location_t locus
= lexer
.peek_token ()->get_locus ();
10901 bool has_ref
= false;
10902 if (lexer
.peek_token ()->get_id () == REF
)
10905 lexer
.skip_token ();
10908 rust_debug ("parsed ref in identifier pattern");
10911 bool has_mut
= false;
10912 if (lexer
.peek_token ()->get_id () == MUT
)
10915 lexer
.skip_token ();
10918 // parse identifier (required)
10919 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
10920 if (ident_tok
== nullptr)
10925 Identifier ident
{ident_tok
};
10928 rust_debug ("parsed identifier in identifier pattern");
10930 // parse optional pattern binding thing
10931 std::unique_ptr
<AST::Pattern
> bind_pattern
= nullptr;
10932 if (lexer
.peek_token ()->get_id () == PATTERN_BIND
)
10934 lexer
.skip_token ();
10936 // parse required pattern to bind
10937 bind_pattern
= parse_pattern ();
10938 if (bind_pattern
== nullptr)
10940 Error
error (lexer
.peek_token ()->get_locus (),
10941 "failed to parse pattern to bind in identifier pattern");
10942 add_error (std::move (error
));
10949 rust_debug ("about to return identifier pattern");
10951 return std::unique_ptr
<AST::IdentifierPattern
> (
10952 new AST::IdentifierPattern (std::move (ident
), locus
, has_ref
, has_mut
,
10953 std::move (bind_pattern
)));
10956 /* Parses a pattern that opens with an identifier. This includes identifier
10957 * patterns, path patterns (and derivatives such as struct patterns, tuple
10958 * struct patterns, and macro invocations), and ranges. */
10959 template <typename ManagedTokenSource
>
10960 std::unique_ptr
<AST::Pattern
>
10961 Parser
<ManagedTokenSource
>::parse_ident_leading_pattern ()
10963 // ensure first token is actually identifier
10964 const_TokenPtr initial_tok
= lexer
.peek_token ();
10965 if (initial_tok
->get_id () != IDENTIFIER
)
10970 // save initial identifier as it may be useful (but don't skip)
10971 std::string initial_ident
= initial_tok
->get_str ();
10973 // parse next tokens as a PathInExpression
10974 AST::PathInExpression path
= parse_path_in_expression ();
10976 // branch on next token
10977 const_TokenPtr t
= lexer
.peek_token ();
10978 switch (t
->get_id ())
10981 return parse_macro_invocation_partial (std::move (path
), AST::AttrVec ());
10984 lexer
.skip_token ();
10987 rust_debug ("parsing tuple struct pattern");
10990 std::unique_ptr
<AST::TupleStructItems
> items
10991 = parse_tuple_struct_items ();
10992 if (items
== nullptr)
10994 Error
error (lexer
.peek_token ()->get_locus (),
10995 "failed to parse tuple struct items");
10996 add_error (std::move (error
));
11002 rust_debug ("successfully parsed tuple struct items");
11004 if (!skip_token (RIGHT_PAREN
))
11010 rust_debug ("successfully parsed tuple struct pattern");
11012 return std::unique_ptr
<AST::TupleStructPattern
> (
11013 new AST::TupleStructPattern (std::move (path
), std::move (items
)));
11017 lexer
.skip_token ();
11019 // parse elements (optional)
11020 AST::StructPatternElements elems
= parse_struct_pattern_elems ();
11022 if (!skip_token (RIGHT_CURLY
))
11028 rust_debug ("successfully parsed struct pattern");
11030 return std::unique_ptr
<AST::StructPattern
> (
11031 new AST::StructPattern (std::move (path
), initial_tok
->get_locus (),
11032 std::move (elems
)));
11038 AST::RangeKind kind
11039 = AST::tokenid_to_rangekind (lexer
.peek_token ()->get_id ());
11041 lexer
.skip_token ();
11043 std::unique_ptr
<AST::RangePatternBoundPath
> lower_bound (
11044 new AST::RangePatternBoundPath (std::move (path
)));
11045 std::unique_ptr
<AST::RangePatternBound
> upper_bound
11046 = parse_range_pattern_bound ();
11048 return std::unique_ptr
<AST::RangePattern
> (
11049 new AST::RangePattern (std::move (lower_bound
),
11050 std::move (upper_bound
), kind
,
11053 case PATTERN_BIND
: {
11054 // only allow on single-segment paths
11055 if (path
.is_single_segment ())
11057 // identifier with pattern bind
11058 lexer
.skip_token ();
11060 std::unique_ptr
<AST::Pattern
> bind_pattern
= parse_pattern ();
11061 if (bind_pattern
== nullptr)
11065 "failed to parse pattern to bind to identifier pattern");
11066 add_error (std::move (error
));
11070 return std::unique_ptr
<AST::IdentifierPattern
> (
11071 new AST::IdentifierPattern (std::move (initial_ident
),
11072 initial_tok
->get_locus (), false,
11073 false, std::move (bind_pattern
)));
11077 "failed to parse pattern bind to a path, not an identifier");
11078 add_error (std::move (error
));
11083 // assume identifier if single segment
11084 if (path
.is_single_segment ())
11086 return std::unique_ptr
<AST::IdentifierPattern
> (
11087 new AST::IdentifierPattern (std::move (initial_ident
),
11088 initial_tok
->get_locus ()));
11090 // return path otherwise
11091 return std::unique_ptr
<AST::PathInExpression
> (
11092 new AST::PathInExpression (std::move (path
)));
11096 // Parses tuple struct items if they exist. Does not parse parentheses.
11097 template <typename ManagedTokenSource
>
11098 std::unique_ptr
<AST::TupleStructItems
>
11099 Parser
<ManagedTokenSource
>::parse_tuple_struct_items ()
11101 std::vector
<std::unique_ptr
<AST::Pattern
>> lower_patterns
;
11104 rust_debug ("started parsing tuple struct items");
11106 // check for '..' at front
11107 if (lexer
.peek_token ()->get_id () == DOT_DOT
)
11109 // only parse upper patterns
11110 lexer
.skip_token ();
11113 rust_debug ("'..' at front in tuple struct items detected");
11115 std::vector
<std::unique_ptr
<AST::Pattern
>> upper_patterns
;
11117 const_TokenPtr t
= lexer
.peek_token ();
11118 while (t
->get_id () == COMMA
)
11120 lexer
.skip_token ();
11122 // break if right paren
11123 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
11126 // parse pattern, which is now required
11127 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
11128 if (pattern
== nullptr)
11130 Error
error (lexer
.peek_token ()->get_locus (),
11131 "failed to parse pattern in tuple struct items");
11132 add_error (std::move (error
));
11136 upper_patterns
.push_back (std::move (pattern
));
11138 t
= lexer
.peek_token ();
11143 "finished parsing tuple struct items ranged (upper/none only)");
11145 return std::unique_ptr
<AST::TupleStructItemsRange
> (
11146 new AST::TupleStructItemsRange (std::move (lower_patterns
),
11147 std::move (upper_patterns
)));
11150 // has at least some lower patterns
11151 const_TokenPtr t
= lexer
.peek_token ();
11152 while (t
->get_id () != RIGHT_PAREN
&& t
->get_id () != DOT_DOT
)
11155 rust_debug ("about to parse pattern in tuple struct items");
11157 // parse pattern, which is required
11158 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
11159 if (pattern
== nullptr)
11161 Error
error (t
->get_locus (),
11162 "failed to parse pattern in tuple struct items");
11163 add_error (std::move (error
));
11167 lower_patterns
.push_back (std::move (pattern
));
11170 rust_debug ("successfully parsed pattern in tuple struct items");
11172 if (lexer
.peek_token ()->get_id () != COMMA
)
11175 rust_debug ("broke out of parsing patterns in tuple struct "
11176 "items as no comma");
11180 lexer
.skip_token ();
11181 t
= lexer
.peek_token ();
11184 // branch on next token
11185 t
= lexer
.peek_token ();
11186 switch (t
->get_id ())
11189 return std::unique_ptr
<AST::TupleStructItemsNoRange
> (
11190 new AST::TupleStructItemsNoRange (std::move (lower_patterns
)));
11192 // has an upper range that must be parsed separately
11193 lexer
.skip_token ();
11195 std::vector
<std::unique_ptr
<AST::Pattern
>> upper_patterns
;
11197 t
= lexer
.peek_token ();
11198 while (t
->get_id () == COMMA
)
11200 lexer
.skip_token ();
11202 // break if next token is right paren
11203 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
11206 // parse pattern, which is required
11207 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
11208 if (pattern
== nullptr)
11210 Error
error (lexer
.peek_token ()->get_locus (),
11211 "failed to parse pattern in tuple struct items");
11212 add_error (std::move (error
));
11216 upper_patterns
.push_back (std::move (pattern
));
11218 t
= lexer
.peek_token ();
11221 return std::unique_ptr
<AST::TupleStructItemsRange
> (
11222 new AST::TupleStructItemsRange (std::move (lower_patterns
),
11223 std::move (upper_patterns
)));
11227 add_error (Error (t
->get_locus (),
11228 "unexpected token %qs in tuple struct items",
11229 t
->get_token_description ()));
11235 // Parses struct pattern elements if they exist.
11236 template <typename ManagedTokenSource
>
11237 AST::StructPatternElements
11238 Parser
<ManagedTokenSource
>::parse_struct_pattern_elems ()
11240 std::vector
<std::unique_ptr
<AST::StructPatternField
>> fields
;
11242 AST::AttrVec etc_attrs
;
11243 bool has_etc
= false;
11245 // try parsing struct pattern fields
11246 const_TokenPtr t
= lexer
.peek_token ();
11247 while (t
->get_id () != RIGHT_CURLY
)
11249 AST::AttrVec outer_attrs
= parse_outer_attributes ();
11251 // parse etc (must be last in struct pattern, so breaks)
11252 if (lexer
.peek_token ()->get_id () == DOT_DOT
)
11254 lexer
.skip_token ();
11255 etc_attrs
= std::move (outer_attrs
);
11260 std::unique_ptr
<AST::StructPatternField
> field
11261 = parse_struct_pattern_field_partial (std::move (outer_attrs
));
11262 if (field
== nullptr)
11264 Error
error (lexer
.peek_token ()->get_locus (),
11265 "failed to parse struct pattern field");
11266 add_error (std::move (error
));
11268 // skip after somewhere?
11269 return AST::StructPatternElements::create_empty ();
11271 fields
.push_back (std::move (field
));
11273 if (lexer
.peek_token ()->get_id () != COMMA
)
11277 lexer
.skip_token ();
11278 t
= lexer
.peek_token ();
11282 return AST::StructPatternElements (std::move (fields
),
11283 std::move (etc_attrs
));
11285 return AST::StructPatternElements (std::move (fields
));
11288 /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
11290 template <typename ManagedTokenSource
>
11291 std::unique_ptr
<AST::StructPatternField
>
11292 Parser
<ManagedTokenSource
>::parse_struct_pattern_field ()
11294 // parse outer attributes (if they exist)
11295 AST::AttrVec outer_attrs
= parse_outer_attributes ();
11297 return parse_struct_pattern_field_partial (std::move (outer_attrs
));
11300 /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
11301 * identifier), with outer attributes passed in. */
11302 template <typename ManagedTokenSource
>
11303 std::unique_ptr
<AST::StructPatternField
>
11304 Parser
<ManagedTokenSource
>::parse_struct_pattern_field_partial (
11305 AST::AttrVec outer_attrs
)
11307 // branch based on next token
11308 const_TokenPtr t
= lexer
.peek_token ();
11309 switch (t
->get_id ())
11311 case INT_LITERAL
: {
11313 std::string index_str
= t
->get_str ();
11314 int index
= atoi (index_str
.c_str ());
11316 lexer
.skip_token ();
11318 if (!skip_token (COLON
))
11323 // parse required pattern
11324 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
11325 if (pattern
== nullptr)
11329 "failed to parse pattern in tuple index struct pattern field");
11330 add_error (std::move (error
));
11335 return std::unique_ptr
<AST::StructPatternFieldTuplePat
> (
11336 new AST::StructPatternFieldTuplePat (index
, std::move (pattern
),
11337 std::move (outer_attrs
),
11341 // identifier-pattern OR only identifier
11342 // branch on next token
11343 switch (lexer
.peek_token (1)->get_id ())
11346 // identifier-pattern
11347 Identifier ident
{t
};
11348 lexer
.skip_token ();
11350 skip_token (COLON
);
11352 // parse required pattern
11353 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
11354 if (pattern
== nullptr)
11356 Error
error (t
->get_locus (),
11357 "failed to parse pattern in struct pattern field");
11358 add_error (std::move (error
));
11363 return std::unique_ptr
<AST::StructPatternFieldIdentPat
> (
11364 new AST::StructPatternFieldIdentPat (std::move (ident
),
11365 std::move (pattern
),
11366 std::move (outer_attrs
),
11370 case RIGHT_CURLY
: {
11372 Identifier ident
= {t
};
11373 lexer
.skip_token ();
11375 return std::unique_ptr
<AST::StructPatternFieldIdent
> (
11376 new AST::StructPatternFieldIdent (std::move (ident
), false, false,
11377 std::move (outer_attrs
),
11382 add_error (Error (t
->get_locus (),
11383 "unrecognised token %qs in struct pattern field",
11384 t
->get_token_description ()));
11391 bool has_ref
= false;
11392 if (t
->get_id () == REF
)
11395 lexer
.skip_token ();
11398 bool has_mut
= false;
11399 if (lexer
.peek_token ()->get_id () == MUT
)
11402 lexer
.skip_token ();
11405 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
11406 if (ident_tok
== nullptr)
11410 Identifier ident
{ident_tok
};
11412 return std::unique_ptr
<AST::StructPatternFieldIdent
> (
11413 new AST::StructPatternFieldIdent (std::move (ident
), has_ref
, has_mut
,
11414 std::move (outer_attrs
),
11418 // not necessarily an error
11423 /* Parses a statement or expression (depending on whether a trailing semicolon
11424 * exists). Useful for block expressions where it cannot be determined through
11425 * lookahead whether it is a statement or expression to be parsed. */
11426 template <typename ManagedTokenSource
>
11428 Parser
<ManagedTokenSource
>::parse_stmt_or_expr ()
11430 // quick exit for empty statement
11431 const_TokenPtr t
= lexer
.peek_token ();
11432 if (t
->get_id () == SEMICOLON
)
11434 lexer
.skip_token ();
11435 std::unique_ptr
<AST::EmptyStmt
> stmt (
11436 new AST::EmptyStmt (t
->get_locus ()));
11437 return ExprOrStmt (std::move (stmt
));
11440 // parse outer attributes
11441 AST::AttrVec outer_attrs
= parse_outer_attributes ();
11442 ParseRestrictions restrictions
;
11443 restrictions
.expr_can_be_stmt
= true;
11444 std::unique_ptr
<AST::Expr
> expr
;
11446 // parsing this will be annoying because of the many different possibilities
11447 /* best may be just to copy paste in parse_item switch, and failing that try
11448 * to parse outer attributes, and then pass them in to either a let
11449 * statement or (fallback) expression statement. */
11450 // FIXME: think of a way to do this without such a large switch?
11452 /* FIXME: for expressions at least, the only way that they can really be
11453 * parsed properly in this way is if they don't support operators on them.
11454 * They must be pratt-parsed otherwise. As such due to composability, only
11455 * explicit statements will have special cases here. This should roughly
11456 * correspond to "expr-with-block", but this warning is here in case it
11457 * isn't the case. */
11458 t
= lexer
.peek_token ();
11459 switch (t
->get_id ())
11463 std::unique_ptr
<AST::LetStmt
> stmt (
11464 parse_let_stmt (std::move (outer_attrs
)));
11465 return ExprOrStmt (std::move (stmt
));
11480 std::unique_ptr
<AST::VisItem
> item (
11481 parse_vis_item (std::move (outer_attrs
)));
11482 return ExprOrStmt (std::move (item
));
11484 /* TODO: implement union keyword but not really because of
11485 * context-dependence crappy hack way to parse a union written below to
11486 * separate it from the good code. */
11488 case UNSAFE
: { // maybe - unsafe traits are a thing
11489 /* if any of these (should be all possible VisItem prefixes), parse a
11490 * VisItem - can't parse item because would require reparsing outer
11492 const_TokenPtr t2
= lexer
.peek_token (1);
11493 switch (t2
->get_id ())
11496 // unsafe block: parse as expression
11497 expr
= parse_expr (std::move (outer_attrs
), restrictions
);
11503 std::unique_ptr
<AST::VisItem
> item (
11504 parse_vis_item (std::move (outer_attrs
)));
11505 return ExprOrStmt (std::move (item
));
11510 std::unique_ptr
<AST::VisItem
> item (
11511 parse_vis_item (std::move (outer_attrs
)));
11512 return ExprOrStmt (std::move (item
));
11515 // unsafe trait impl
11516 std::unique_ptr
<AST::VisItem
> item (
11517 parse_vis_item (std::move (outer_attrs
)));
11518 return ExprOrStmt (std::move (item
));
11521 add_error (Error (t2
->get_locus (),
11522 "unrecognised token %qs after parsing unsafe - "
11523 "expected beginning of expression or statement",
11524 t
->get_token_description ()));
11527 return ExprOrStmt::create_error ();
11531 /* FIXME: this is either a macro invocation or macro invocation semi.
11532 * start parsing to determine which one it is. */
11533 // FIXME: old code there
11535 // crappy hack to do union "keyword"
11537 if (t
->get_str () == Values::WeakKeywords::UNION
11538 && lexer
.peek_token (1)->get_id () == IDENTIFIER
)
11540 std::unique_ptr
<AST::VisItem
> item (
11541 parse_vis_item (std::move (outer_attrs
)));
11542 return ExprOrStmt (std::move (item
));
11543 // or should this go straight to parsing union?
11545 else if (t
->get_str () == Values::WeakKeywords::MACRO_RULES
11546 && lexer
.peek_token (1)->get_id () == EXCLAM
)
11548 // macro_rules! macro item
11549 std::unique_ptr
<AST::Item
> item (
11550 parse_macro_rules_def (std::move (outer_attrs
)));
11551 return ExprOrStmt (std::move (item
));
11553 gcc_fallthrough ();
11558 case SCOPE_RESOLUTION
:
11559 case DOLLAR_SIGN
: {
11560 AST::PathInExpression path
= parse_path_in_expression ();
11561 std::unique_ptr
<AST::Expr
> null_denotation
;
11563 if (lexer
.peek_token ()->get_id () == EXCLAM
)
11565 std::unique_ptr
<AST::MacroInvocation
> invoc
11566 = parse_macro_invocation_partial (std::move (path
),
11567 std::move (outer_attrs
));
11569 if (restrictions
.consume_semi
&& maybe_skip_token (SEMICOLON
))
11571 invoc
->add_semicolon ();
11572 // Macro invocation with semicolon.
11573 return ExprOrStmt (
11574 std::unique_ptr
<AST::Stmt
> (std::move (invoc
)));
11577 TokenId after_macro
= lexer
.peek_token ()->get_id ();
11579 if (invoc
->get_invoc_data ().get_delim_tok_tree ().get_delim_type ()
11581 && after_macro
!= DOT
&& after_macro
!= QUESTION_MARK
)
11583 rust_debug ("braced macro statement");
11584 return ExprOrStmt (
11585 std::unique_ptr
<AST::Stmt
> (std::move (invoc
)));
11588 null_denotation
= std::move (invoc
);
11593 = null_denotation_path (std::move (path
), {}, restrictions
);
11596 expr
= left_denotations (std::move (null_denotation
), LBP_LOWEST
,
11597 std::move (outer_attrs
), restrictions
);
11601 /* expression statement or expression itself - parse
11602 * expression then make it statement if semi afterwards */
11603 expr
= parse_expr (std::move (outer_attrs
), restrictions
);
11607 const_TokenPtr after_expr
= lexer
.peek_token ();
11608 if (after_expr
->get_id () == SEMICOLON
)
11610 // must be expression statement
11611 lexer
.skip_token ();
11615 std::unique_ptr
<AST::ExprStmt
> stmt (
11616 new AST::ExprStmt (std::move (expr
), t
->get_locus (), true));
11617 return ExprOrStmt (std::move (stmt
));
11621 return ExprOrStmt::create_error ();
11625 if (expr
&& !expr
->is_expr_without_block ()
11626 && after_expr
->get_id () != RIGHT_CURLY
)
11628 // block expression statement.
11629 std::unique_ptr
<AST::ExprStmt
> stmt (
11630 new AST::ExprStmt (std::move (expr
), t
->get_locus (), false));
11631 return ExprOrStmt (std::move (stmt
));
11634 // return expression
11635 return ExprOrStmt (std::move (expr
));
11638 // Parses a struct expression field.
11639 template <typename ManagedTokenSource
>
11640 std::unique_ptr
<AST::StructExprField
>
11641 Parser
<ManagedTokenSource
>::parse_struct_expr_field ()
11643 AST::AttrVec outer_attrs
= parse_outer_attributes ();
11644 const_TokenPtr t
= lexer
.peek_token ();
11645 switch (t
->get_id ())
11648 if (lexer
.peek_token (1)->get_id () == COLON
)
11650 // struct expr field with identifier and expr
11651 Identifier ident
= {t
};
11652 lexer
.skip_token (1);
11654 // parse expression (required)
11655 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
11656 if (expr
== nullptr)
11658 Error
error (t
->get_locus (),
11659 "failed to parse struct expression field with "
11660 "identifier and expression");
11661 add_error (std::move (error
));
11666 return std::unique_ptr
<AST::StructExprFieldIdentifierValue
> (
11667 new AST::StructExprFieldIdentifierValue (std::move (ident
),
11669 std::move (outer_attrs
),
11674 // struct expr field with identifier only
11675 Identifier ident
{t
};
11676 lexer
.skip_token ();
11678 return std::unique_ptr
<AST::StructExprFieldIdentifier
> (
11679 new AST::StructExprFieldIdentifier (std::move (ident
),
11680 std::move (outer_attrs
),
11683 case INT_LITERAL
: {
11684 // parse tuple index field
11685 int index
= atoi (t
->get_str ().c_str ());
11686 lexer
.skip_token ();
11688 if (!skip_token (COLON
))
11694 // parse field expression (required)
11695 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
11696 if (expr
== nullptr)
11698 Error
error (t
->get_locus (),
11699 "failed to parse expr in struct (or enum) expr "
11700 "field with tuple index");
11701 add_error (std::move (error
));
11706 return std::unique_ptr
<AST::StructExprFieldIndexValue
> (
11707 new AST::StructExprFieldIndexValue (index
, std::move (expr
),
11708 std::move (outer_attrs
),
11712 /* this is a struct base and can't be parsed here, so just return
11713 * nothing without erroring */
11718 Error (t
->get_locus (),
11719 "unrecognised token %qs as first token of struct expr field - "
11720 "expected identifier or integer literal",
11721 t
->get_token_description ()));
11727 // "Unexpected token" panic mode - flags gcc error at unexpected token
11728 template <typename ManagedTokenSource
>
11730 Parser
<ManagedTokenSource
>::unexpected_token (const_TokenPtr t
)
11732 Error
error (t
->get_locus (), "unexpected token %qs\n",
11733 t
->get_token_description ());
11734 add_error (std::move (error
));
11737 /* Crappy "error recovery" performed after error by skipping tokens until a
11738 * semi-colon is found */
11739 template <typename ManagedTokenSource
>
11741 Parser
<ManagedTokenSource
>::skip_after_semicolon ()
11743 const_TokenPtr t
= lexer
.peek_token ();
11745 while (t
->get_id () != END_OF_FILE
&& t
->get_id () != SEMICOLON
)
11747 lexer
.skip_token ();
11748 t
= lexer
.peek_token ();
11751 if (t
->get_id () == SEMICOLON
)
11752 lexer
.skip_token ();
11755 /* Skips the current token */
11756 template <typename ManagedTokenSource
>
11758 Parser
<ManagedTokenSource
>::skip_token ()
11760 lexer
.skip_token ();
11763 /* Checks if current token has inputted id - skips it and returns true if so,
11764 * diagnoses an error and returns false otherwise. */
11765 template <typename ManagedTokenSource
>
11767 Parser
<ManagedTokenSource
>::skip_token (TokenId token_id
)
11769 return expect_token (token_id
) != const_TokenPtr ();
11772 /* Checks if current token is similar to inputted token - skips it and returns
11773 * true if so, diagnoses an error and returns false otherwise. */
11774 template <typename ManagedTokenSource
>
11776 Parser
<ManagedTokenSource
>::skip_token (const_TokenPtr token
)
11778 return expect_token (token
) != const_TokenPtr ();
11781 /* Checks if current token has inputted id - skips it and returns true if so,
11782 * returns false otherwise without diagnosing an error */
11783 template <typename ManagedTokenSource
>
11785 Parser
<ManagedTokenSource
>::maybe_skip_token (TokenId token_id
)
11787 if (lexer
.peek_token ()->get_id () != token_id
)
11790 return skip_token (token_id
);
11793 /* Checks the current token - if id is same as expected, skips and returns it,
11794 * otherwise diagnoses error and returns null. */
11795 template <typename ManagedTokenSource
>
11797 Parser
<ManagedTokenSource
>::expect_token (TokenId token_id
)
11799 const_TokenPtr t
= lexer
.peek_token ();
11800 if (t
->get_id () == token_id
)
11802 lexer
.skip_token ();
11807 Error
error (t
->get_locus (), "expecting %qs but %qs found",
11808 get_token_description (token_id
),
11809 t
->get_token_description ());
11810 add_error (std::move (error
));
11812 return const_TokenPtr ();
11816 /* Checks the current token - if same as expected, skips and returns it,
11817 * otherwise diagnoses error and returns null. */
11818 template <typename ManagedTokenSource
>
11820 Parser
<ManagedTokenSource
>::expect_token (const_TokenPtr token_expect
)
11822 const_TokenPtr t
= lexer
.peek_token ();
11823 if (t
->get_id () == token_expect
->get_id ()
11824 && (!t
->should_have_str () || t
->get_str () == token_expect
->get_str ()))
11826 lexer
.skip_token ();
11831 Error
error (t
->get_locus (), "expecting %qs but %qs found",
11832 token_expect
->get_token_description (),
11833 t
->get_token_description ());
11834 add_error (std::move (error
));
11836 return const_TokenPtr ();
11840 // Skips all tokens until EOF or }. Don't use.
11841 template <typename ManagedTokenSource
>
11843 Parser
<ManagedTokenSource
>::skip_after_end ()
11845 const_TokenPtr t
= lexer
.peek_token ();
11847 while (t
->get_id () != END_OF_FILE
&& t
->get_id () != RIGHT_CURLY
)
11849 lexer
.skip_token ();
11850 t
= lexer
.peek_token ();
11853 if (t
->get_id () == RIGHT_CURLY
)
11855 lexer
.skip_token ();
11859 /* A slightly more aware error-handler that skips all tokens until it reaches
11860 * the end of the block scope (i.e. when left curly brackets = right curly
11861 * brackets). Note: assumes currently in the middle of a block. Use
11862 * skip_after_next_block to skip based on the assumption that the block
11863 * has not been entered yet. */
11864 template <typename ManagedTokenSource
>
11866 Parser
<ManagedTokenSource
>::skip_after_end_block ()
11868 const_TokenPtr t
= lexer
.peek_token ();
11869 int curly_count
= 1;
11871 while (curly_count
> 0 && t
->get_id () != END_OF_FILE
)
11873 switch (t
->get_id ())
11884 lexer
.skip_token ();
11885 t
= lexer
.peek_token ();
11889 /* Skips tokens until the end of the next block. i.e. assumes that the block
11890 * has not been entered yet. */
11891 template <typename ManagedTokenSource
>
11893 Parser
<ManagedTokenSource
>::skip_after_next_block ()
11895 const_TokenPtr t
= lexer
.peek_token ();
11897 // initial loop - skip until EOF if no left curlies encountered
11898 while (t
->get_id () != END_OF_FILE
&& t
->get_id () != LEFT_CURLY
)
11900 lexer
.skip_token ();
11902 t
= lexer
.peek_token ();
11905 // if next token is left, skip it and then skip after the block ends
11906 if (t
->get_id () == LEFT_CURLY
)
11908 lexer
.skip_token ();
11910 skip_after_end_block ();
11912 // otherwise, do nothing as EOF
11915 /* Skips all tokens until ] (the end of an attribute) - does not skip the ]
11916 * (as designed for attribute body use) */
11917 template <typename ManagedTokenSource
>
11919 Parser
<ManagedTokenSource
>::skip_after_end_attribute ()
11921 const_TokenPtr t
= lexer
.peek_token ();
11923 while (t
->get_id () != RIGHT_SQUARE
)
11925 lexer
.skip_token ();
11926 t
= lexer
.peek_token ();
11929 // Don't skip the RIGHT_SQUARE token
11932 /* Pratt parser impl of parse_expr. FIXME: this is only provisional and
11933 * probably will be changed. */
11934 template <typename ManagedTokenSource
>
11935 std::unique_ptr
<AST::Expr
>
11936 Parser
<ManagedTokenSource
>::parse_expr (int right_binding_power
,
11937 AST::AttrVec outer_attrs
,
11938 ParseRestrictions restrictions
)
11940 const_TokenPtr current_token
= lexer
.peek_token ();
11941 // Special hack because we are allowed to return nullptr, in that case we
11942 // don't want to skip the token, since we don't actually parse it. But if
11943 // null isn't allowed it indicates an error, and we want to skip past that.
11944 // So return early if it is one of the tokens that ends an expression
11945 // (or at least cannot start a new expression).
11946 if (restrictions
.expr_can_be_null
)
11948 TokenId id
= current_token
->get_id ();
11949 if (id
== SEMICOLON
|| id
== RIGHT_PAREN
|| id
== RIGHT_CURLY
11950 || id
== RIGHT_SQUARE
|| id
== COMMA
|| id
== LEFT_CURLY
)
11954 if (current_token
->get_id () == LEFT_SHIFT
)
11956 lexer
.split_current_token (LEFT_ANGLE
, LEFT_ANGLE
);
11957 current_token
= lexer
.peek_token ();
11960 lexer
.skip_token ();
11962 ParseRestrictions null_denotation_restrictions
= restrictions
;
11963 null_denotation_restrictions
.expr_can_be_stmt
= false;
11965 // parse null denotation (unary part of expression)
11966 std::unique_ptr
<AST::Expr
> expr
11967 = null_denotation (current_token
, {}, null_denotation_restrictions
);
11969 return left_denotations (std::move (expr
), right_binding_power
,
11970 std::move (outer_attrs
), restrictions
);
11973 template <typename ManagedTokenSource
>
11974 std::unique_ptr
<AST::Expr
>
11975 Parser
<ManagedTokenSource
>::left_denotations (std::unique_ptr
<AST::Expr
> expr
,
11976 int right_binding_power
,
11977 AST::AttrVec outer_attrs
,
11978 ParseRestrictions restrictions
)
11980 if (expr
== nullptr)
11983 rust_debug ("null denotation is null; returning null for parse_expr");
11987 const_TokenPtr current_token
= lexer
.peek_token ();
11989 if (restrictions
.expr_can_be_stmt
&& !expr
->is_expr_without_block ()
11990 && current_token
->get_id () != DOT
11991 && current_token
->get_id () != QUESTION_MARK
)
11993 rust_debug ("statement expression with block");
11994 expr
->set_outer_attrs (std::move (outer_attrs
));
11998 restrictions
.expr_can_be_stmt
= false;
12000 // stop parsing if find lower priority token - parse higher priority first
12001 while (right_binding_power
< left_binding_power (current_token
))
12003 lexer
.skip_token ();
12005 // FIXME attributes should generally be applied to the null denotation.
12006 expr
= left_denotation (current_token
, std::move (expr
),
12007 std::move (outer_attrs
), restrictions
);
12009 if (expr
== nullptr)
12012 rust_debug ("left denotation is null; returning null for parse_expr");
12017 current_token
= lexer
.peek_token ();
12023 // Parse expression with lowest left binding power.
12024 template <typename ManagedTokenSource
>
12025 std::unique_ptr
<AST::Expr
>
12026 Parser
<ManagedTokenSource
>::parse_expr (AST::AttrVec outer_attrs
,
12027 ParseRestrictions restrictions
)
12029 return parse_expr (LBP_LOWEST
, std::move (outer_attrs
), restrictions
);
12032 /* Determines action to take when finding token at beginning of expression. */
12033 template <typename ManagedTokenSource
>
12034 std::unique_ptr
<AST::Expr
>
12035 Parser
<ManagedTokenSource
>::null_denotation (const_TokenPtr tok
,
12036 AST::AttrVec outer_attrs
,
12037 ParseRestrictions restrictions
)
12039 /* note: tok is previous character in input stream, not current one, as
12040 * parse_expr skips it before passing it in */
12042 /* as a Pratt parser (which works by decomposing expressions into a null
12043 * denotation and then a left denotation), null denotations handle primaries
12044 * and unary operands (but only prefix unary operands) */
12046 switch (tok
->get_id ())
12055 rust_debug ("beginning null denotation identifier handling");
12057 /* best option: parse as path, then extract identifier, macro,
12058 * struct/enum, or just path info from it */
12059 AST::PathInExpression path
= parse_path_in_expression_pratt (tok
);
12061 return null_denotation_path (std::move (path
), std::move (outer_attrs
),
12064 case SCOPE_RESOLUTION
: {
12065 // TODO: fix: this is for global paths, i.e. std::string::whatever
12066 Error
error (tok
->get_locus (),
12067 "found null denotation scope resolution operator, and "
12068 "have not written handling for it");
12069 add_error (std::move (error
));
12074 return null_denotation_not_path (std::move (tok
), std::move (outer_attrs
),
12079 // Handling of expresions that start with a path for `null_denotation`.
12080 template <typename ManagedTokenSource
>
12081 std::unique_ptr
<AST::Expr
>
12082 Parser
<ManagedTokenSource
>::null_denotation_path (
12083 AST::PathInExpression path
, AST::AttrVec outer_attrs
,
12084 ParseRestrictions restrictions
)
12086 rust_debug ("parsing null denotation after path");
12088 // HACK: always make "self" by itself a path (regardless of next
12090 if (path
.is_single_segment () && path
.get_segments ()[0].is_lower_self_seg ())
12092 // HACK: add outer attrs to path
12093 path
.set_outer_attrs (std::move (outer_attrs
));
12094 return std::unique_ptr
<AST::PathInExpression
> (
12095 new AST::PathInExpression (std::move (path
)));
12098 // branch on next token
12099 const_TokenPtr t
= lexer
.peek_token ();
12100 switch (t
->get_id ())
12104 return parse_macro_invocation_partial (std::move (path
),
12105 std::move (outer_attrs
));
12107 bool not_a_block
= lexer
.peek_token (1)->get_id () == IDENTIFIER
12108 && (lexer
.peek_token (2)->get_id () == COMMA
12109 || (lexer
.peek_token (2)->get_id () == COLON
12110 && (lexer
.peek_token (4)->get_id () == COMMA
12111 || !can_tok_start_type (
12112 lexer
.peek_token (3)->get_id ()))));
12114 /* definitely not a block:
12115 * path '{' ident ','
12116 * path '{' ident ':' [anything] ','
12117 * path '{' ident ':' [not a type]
12118 * otherwise, assume block expr and thus path */
12120 rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ",
12121 lexer
.peek_token (1)->get_token_description (),
12122 lexer
.peek_token (2)->get_token_description (),
12123 lexer
.peek_token (3)->get_token_description (),
12124 lexer
.peek_token (4)->get_token_description ());
12126 rust_debug ("can be struct expr: '%s', not a block: '%s'",
12127 restrictions
.can_be_struct_expr
? "true" : "false",
12128 not_a_block
? "true" : "false");
12130 // struct/enum expr struct
12131 if (!restrictions
.can_be_struct_expr
&& !not_a_block
)
12133 // HACK: add outer attrs to path
12134 path
.set_outer_attrs (std::move (outer_attrs
));
12135 return std::unique_ptr
<AST::PathInExpression
> (
12136 new AST::PathInExpression (std::move (path
)));
12138 return parse_struct_expr_struct_partial (std::move (path
),
12139 std::move (outer_attrs
));
12142 // struct/enum expr tuple
12143 if (!restrictions
.can_be_struct_expr
)
12145 // assume path is returned
12146 // HACK: add outer attributes to path
12147 path
.set_outer_attrs (std::move (outer_attrs
));
12148 return std::unique_ptr
<AST::PathInExpression
> (
12149 new AST::PathInExpression (std::move (path
)));
12151 return parse_struct_expr_tuple_partial (std::move (path
),
12152 std::move (outer_attrs
));
12154 // assume path is returned if not single segment
12155 if (path
.is_single_segment ())
12157 // FIXME: This should probably be returned as a path.
12158 /* HACK: may have to become permanent, but this is my current
12159 * identifier expression */
12160 return std::unique_ptr
<AST::IdentifierExpr
> (new AST::IdentifierExpr (
12161 path
.get_segments ()[0].get_ident_segment ().as_string (), {},
12162 path
.get_locus ()));
12164 // HACK: add outer attrs to path
12165 path
.set_outer_attrs (std::move (outer_attrs
));
12166 return std::unique_ptr
<AST::PathInExpression
> (
12167 new AST::PathInExpression (std::move (path
)));
12169 rust_unreachable ();
12172 // Handling of expresions that do not start with a path for `null_denotation`.
12173 template <typename ManagedTokenSource
>
12174 std::unique_ptr
<AST::Expr
>
12175 Parser
<ManagedTokenSource
>::null_denotation_not_path (
12176 const_TokenPtr tok
, AST::AttrVec outer_attrs
, ParseRestrictions restrictions
)
12178 switch (tok
->get_id ())
12180 // FIXME: Handle in null_denotation_path?
12184 // HACK: add outer attrs to path
12185 AST::QualifiedPathInExpression path
12186 = parse_qualified_path_in_expression (tok
->get_locus ());
12187 path
.set_outer_attrs (std::move (outer_attrs
));
12188 return std::unique_ptr
<AST::QualifiedPathInExpression
> (
12189 new AST::QualifiedPathInExpression (std::move (path
)));
12191 // FIXME: delegate to parse_literal_expr instead? would have to rejig
12192 // tokens and whatever.
12193 // FIXME: for literal exprs, outer attrs should be passed in, and later
12194 // error if it does not make up the entire statement.
12196 // we should check the range, but ignore for now
12198 return std::unique_ptr
<AST::LiteralExpr
> (
12199 new AST::LiteralExpr (tok
->get_str (), AST::Literal::INT
,
12200 tok
->get_type_hint (), {}, tok
->get_locus ()));
12201 case FLOAT_LITERAL
:
12202 // encode as float?
12203 return std::unique_ptr
<AST::LiteralExpr
> (
12204 new AST::LiteralExpr (tok
->get_str (), AST::Literal::FLOAT
,
12205 tok
->get_type_hint (), {}, tok
->get_locus ()));
12206 case STRING_LITERAL
:
12207 return std::unique_ptr
<AST::LiteralExpr
> (
12208 new AST::LiteralExpr (tok
->get_str (), AST::Literal::STRING
,
12209 tok
->get_type_hint (), {}, tok
->get_locus ()));
12210 case BYTE_STRING_LITERAL
:
12211 return std::unique_ptr
<AST::LiteralExpr
> (
12212 new AST::LiteralExpr (tok
->get_str (), AST::Literal::BYTE_STRING
,
12213 tok
->get_type_hint (), {}, tok
->get_locus ()));
12214 case RAW_STRING_LITERAL
:
12215 return std::unique_ptr
<AST::LiteralExpr
> (
12216 new AST::LiteralExpr (tok
->get_str (), AST::Literal::RAW_STRING
,
12217 tok
->get_type_hint (), {}, tok
->get_locus ()));
12219 return std::unique_ptr
<AST::LiteralExpr
> (
12220 new AST::LiteralExpr (tok
->get_str (), AST::Literal::CHAR
,
12221 tok
->get_type_hint (), {}, tok
->get_locus ()));
12222 case BYTE_CHAR_LITERAL
:
12223 return std::unique_ptr
<AST::LiteralExpr
> (
12224 new AST::LiteralExpr (tok
->get_str (), AST::Literal::BYTE
,
12225 tok
->get_type_hint (), {}, tok
->get_locus ()));
12227 return std::unique_ptr
<AST::LiteralExpr
> (
12228 new AST::LiteralExpr (Values::Keywords::TRUE_LITERAL
,
12229 AST::Literal::BOOL
, tok
->get_type_hint (), {},
12230 tok
->get_locus ()));
12231 case FALSE_LITERAL
:
12232 return std::unique_ptr
<AST::LiteralExpr
> (
12233 new AST::LiteralExpr (Values::Keywords::FALSE_LITERAL
,
12234 AST::Literal::BOOL
, tok
->get_type_hint (), {},
12235 tok
->get_locus ()));
12237 return parse_grouped_or_tuple_expr (std::move (outer_attrs
),
12238 tok
->get_locus ());
12240 /*case PLUS: { // unary plus operator
12241 // invoke parse_expr recursively with appropriate priority, etc. for
12242 below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS);
12244 if (expr == nullptr)
12246 // can only apply to integer and float expressions
12247 if (expr->get_type() != integer_type_node || expr->get_type() !=
12248 float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
12249 plus must be int or float but it is %s", print_type(expr->get_type()));
12253 return Tree(expr, tok->get_locus());
12255 // Rust has no unary plus operator
12256 case MINUS
: { // unary minus
12257 ParseRestrictions entered_from_unary
;
12258 entered_from_unary
.entered_from_unary
= true;
12259 if (!restrictions
.can_be_struct_expr
)
12260 entered_from_unary
.can_be_struct_expr
= false;
12261 std::unique_ptr
<AST::Expr
> expr
12262 = parse_expr (LBP_UNARY_MINUS
, {}, entered_from_unary
);
12264 if (expr
== nullptr)
12266 // can only apply to integer and float expressions
12267 /*if (expr.get_type() != integer_type_node || expr.get_type() !=
12268 float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
12269 minus must be int or float but it is %s",
12270 print_type(expr.get_type())); return Tree::error();
12272 /* FIXME: when implemented the "get type" method on expr, ensure it is
12273 * int or float type (except unsigned int). Actually, this would
12274 * probably have to be done in semantic analysis (as type checking).
12277 /* FIXME: allow outer attributes on these expressions by having an
12278 * outer attrs parameter in function*/
12279 return std::unique_ptr
<AST::NegationExpr
> (
12280 new AST::NegationExpr (std::move (expr
), NegationOperator::NEGATE
,
12281 std::move (outer_attrs
), tok
->get_locus ()));
12283 case EXCLAM
: { // logical or bitwise not
12284 ParseRestrictions entered_from_unary
;
12285 entered_from_unary
.entered_from_unary
= true;
12286 if (!restrictions
.can_be_struct_expr
)
12287 entered_from_unary
.can_be_struct_expr
= false;
12288 std::unique_ptr
<AST::Expr
> expr
12289 = parse_expr (LBP_UNARY_EXCLAM
, {}, entered_from_unary
);
12291 if (expr
== nullptr)
12293 // can only apply to boolean expressions
12294 /*if (expr.get_type() != boolean_type_node) {
12295 rust_error_at(tok->get_locus(),
12296 "operand of logical not must be a boolean but it is %s",
12297 print_type(expr.get_type()));
12298 return Tree::error();
12300 /* FIXME: type checking for boolean or integer expressions in semantic
12303 // FIXME: allow outer attributes on these expressions
12304 return std::unique_ptr
<AST::NegationExpr
> (
12305 new AST::NegationExpr (std::move (expr
), NegationOperator::NOT
,
12306 std::move (outer_attrs
), tok
->get_locus ()));
12309 /* pointer dereference only - HACK: as struct expressions should
12310 * always be value expressions, cannot be dereferenced */
12311 ParseRestrictions entered_from_unary
;
12312 entered_from_unary
.entered_from_unary
= true;
12313 entered_from_unary
.can_be_struct_expr
= false;
12314 std::unique_ptr
<AST::Expr
> expr
12315 = parse_expr (LBP_UNARY_ASTERISK
, {}, entered_from_unary
);
12316 // FIXME: allow outer attributes on expression
12317 return std::unique_ptr
<AST::DereferenceExpr
> (
12318 new AST::DereferenceExpr (std::move (expr
), std::move (outer_attrs
),
12319 tok
->get_locus ()));
12322 // (single) "borrow" expression - shared (mutable) or immutable
12323 std::unique_ptr
<AST::Expr
> expr
= nullptr;
12324 Mutability mutability
= Mutability::Imm
;
12325 bool raw_borrow
= false;
12327 ParseRestrictions entered_from_unary
;
12328 entered_from_unary
.entered_from_unary
= true;
12329 if (!restrictions
.can_be_struct_expr
)
12330 entered_from_unary
.can_be_struct_expr
= false;
12332 auto is_mutability
= [] (const_TokenPtr token
) {
12333 return token
->get_id () == CONST
|| token
->get_id () == MUT
;
12336 auto t
= lexer
.peek_token ();
12337 // Weak raw keyword, we look (1) ahead and treat it as an identifier if
12338 // there is no mut nor const.
12339 if (t
->get_id () == IDENTIFIER
12340 && t
->get_str () == Values::WeakKeywords::RAW
12341 && is_mutability (lexer
.peek_token (1)))
12343 lexer
.skip_token ();
12344 switch (lexer
.peek_token ()->get_id ())
12347 mutability
= Mutability::Mut
;
12350 mutability
= Mutability::Imm
;
12353 rust_error_at (lexer
.peek_token ()->get_locus (),
12354 "raw borrow should be either const or mut");
12356 lexer
.skip_token ();
12357 expr
= parse_expr (LBP_UNARY_AMP_MUT
, {}, entered_from_unary
);
12360 else if (t
->get_id () == MUT
)
12362 lexer
.skip_token ();
12363 expr
= parse_expr (LBP_UNARY_AMP_MUT
, {}, entered_from_unary
);
12364 mutability
= Mutability::Mut
;
12365 raw_borrow
= false;
12369 expr
= parse_expr (LBP_UNARY_AMP
, {}, entered_from_unary
);
12370 raw_borrow
= false;
12373 // FIXME: allow outer attributes on expression
12374 return std::unique_ptr
<AST::BorrowExpr
> (
12375 new AST::BorrowExpr (std::move (expr
), mutability
, raw_borrow
, false,
12376 std::move (outer_attrs
), tok
->get_locus ()));
12378 case LOGICAL_AND
: {
12379 // (double) "borrow" expression - shared (mutable) or immutable
12380 std::unique_ptr
<AST::Expr
> expr
= nullptr;
12381 Mutability mutability
= Mutability::Imm
;
12383 ParseRestrictions entered_from_unary
;
12384 entered_from_unary
.entered_from_unary
= true;
12386 if (lexer
.peek_token ()->get_id () == MUT
)
12388 lexer
.skip_token ();
12389 expr
= parse_expr (LBP_UNARY_AMP_MUT
, {}, entered_from_unary
);
12390 mutability
= Mutability::Mut
;
12394 expr
= parse_expr (LBP_UNARY_AMP
, {}, entered_from_unary
);
12395 mutability
= Mutability::Imm
;
12398 // FIXME: allow outer attributes on expression
12399 return std::unique_ptr
<AST::BorrowExpr
> (
12400 new AST::BorrowExpr (std::move (expr
), mutability
, false, true,
12401 std::move (outer_attrs
), tok
->get_locus ()));
12406 // closure expression
12407 return parse_closure_expr_pratt (tok
, std::move (outer_attrs
));
12409 // either "range to" or "range full" expressions
12410 return parse_nud_range_exclusive_expr (tok
, std::move (outer_attrs
));
12412 // range to inclusive expr
12413 return parse_range_to_inclusive_expr (tok
, std::move (outer_attrs
));
12415 // FIXME: is this really a null denotation expression?
12416 return parse_return_expr (std::move (outer_attrs
), tok
->get_locus ());
12418 // FIXME: is this really a null denotation expression?
12419 return parse_break_expr (std::move (outer_attrs
), tok
->get_locus ());
12421 return parse_continue_expr (std::move (outer_attrs
), tok
->get_locus ());
12423 // ok - this is an expression with block for once.
12424 return parse_block_expr (std::move (outer_attrs
), tl::nullopt
,
12425 tok
->get_locus ());
12427 // if or if let, so more lookahead to find out
12428 if (lexer
.peek_token ()->get_id () == LET
)
12431 return parse_if_let_expr (std::move (outer_attrs
), tok
->get_locus ());
12436 return parse_if_expr (std::move (outer_attrs
), tok
->get_locus ());
12439 return parse_labelled_loop_expr (tok
, std::move (outer_attrs
));
12441 return parse_loop_expr (std::move (outer_attrs
), tl::nullopt
,
12442 tok
->get_locus ());
12444 if (lexer
.peek_token ()->get_id () == LET
)
12446 return parse_while_let_loop_expr (std::move (outer_attrs
));
12450 return parse_while_loop_expr (std::move (outer_attrs
), tl::nullopt
,
12451 tok
->get_locus ());
12454 return parse_for_loop_expr (std::move (outer_attrs
), tl::nullopt
);
12456 // also an expression with block
12457 return parse_match_expr (std::move (outer_attrs
), tok
->get_locus ());
12459 // array definition expr (not indexing)
12460 return parse_array_expr (std::move (outer_attrs
), tok
->get_locus ());
12462 return parse_unsafe_block_expr (std::move (outer_attrs
),
12463 tok
->get_locus ());
12465 return parse_box_expr (std::move (outer_attrs
), tok
->get_locus ());
12468 Error (tok
->get_locus (),
12469 "use of %qs is not allowed on the right-side of an assignment",
12470 tok
->get_token_description ()));
12473 if (!restrictions
.expr_can_be_null
)
12474 add_error (Error (tok
->get_locus (),
12475 "found unexpected token %qs in null denotation",
12476 tok
->get_token_description ()));
12481 /* Called for each token that can appear in infix (between) position. Can be
12482 * operators or other punctuation. Returns a function pointer to member
12483 * function that implements the left denotation for the token given. */
12484 template <typename ManagedTokenSource
>
12485 std::unique_ptr
<AST::Expr
>
12486 Parser
<ManagedTokenSource
>::left_denotation (const_TokenPtr tok
,
12487 std::unique_ptr
<AST::Expr
> left
,
12488 AST::AttrVec outer_attrs
,
12489 ParseRestrictions restrictions
)
12491 // Token passed in has already been skipped, so peek gives "next" token
12492 switch (tok
->get_id ())
12494 // FIXME: allow for outer attributes to be applied
12495 case QUESTION_MARK
: {
12496 location_t left_locus
= left
->get_locus ();
12497 // error propagation expression - unary postfix
12498 return std::unique_ptr
<AST::ErrorPropagationExpr
> (
12499 new AST::ErrorPropagationExpr (std::move (left
),
12500 std::move (outer_attrs
), left_locus
));
12503 // sum expression - binary infix
12504 /*return parse_binary_plus_expr (tok, std::move (left),
12505 std::move (outer_attrs), restrictions);*/
12506 return parse_arithmetic_or_logical_expr (tok
, std::move (left
),
12507 std::move (outer_attrs
),
12508 ArithmeticOrLogicalOperator::ADD
,
12511 // difference expression - binary infix
12512 /*return parse_binary_minus_expr (tok, std::move (left),
12513 std::move (outer_attrs),
12515 return parse_arithmetic_or_logical_expr (
12516 tok
, std::move (left
), std::move (outer_attrs
),
12517 ArithmeticOrLogicalOperator::SUBTRACT
, restrictions
);
12519 // product expression - binary infix
12520 /*return parse_binary_mult_expr (tok, std::move (left),
12521 std::move (outer_attrs), restrictions);*/
12522 return parse_arithmetic_or_logical_expr (
12523 tok
, std::move (left
), std::move (outer_attrs
),
12524 ArithmeticOrLogicalOperator::MULTIPLY
, restrictions
);
12526 // quotient expression - binary infix
12527 /*return parse_binary_div_expr (tok, std::move (left),
12528 std::move (outer_attrs), restrictions);*/
12529 return parse_arithmetic_or_logical_expr (
12530 tok
, std::move (left
), std::move (outer_attrs
),
12531 ArithmeticOrLogicalOperator::DIVIDE
, restrictions
);
12533 // modulo expression - binary infix
12534 /*return parse_binary_mod_expr (tok, std::move (left),
12535 std::move (outer_attrs), restrictions);*/
12536 return parse_arithmetic_or_logical_expr (
12537 tok
, std::move (left
), std::move (outer_attrs
),
12538 ArithmeticOrLogicalOperator::MODULUS
, restrictions
);
12540 // logical or bitwise and expression - binary infix
12541 /*return parse_bitwise_and_expr (tok, std::move (left),
12542 std::move (outer_attrs), restrictions);*/
12543 return parse_arithmetic_or_logical_expr (
12544 tok
, std::move (left
), std::move (outer_attrs
),
12545 ArithmeticOrLogicalOperator::BITWISE_AND
, restrictions
);
12547 // logical or bitwise or expression - binary infix
12548 /*return parse_bitwise_or_expr (tok, std::move (left),
12549 std::move (outer_attrs), restrictions);*/
12550 return parse_arithmetic_or_logical_expr (
12551 tok
, std::move (left
), std::move (outer_attrs
),
12552 ArithmeticOrLogicalOperator::BITWISE_OR
, restrictions
);
12554 // logical or bitwise xor expression - binary infix
12555 /*return parse_bitwise_xor_expr (tok, std::move (left),
12556 std::move (outer_attrs), restrictions);*/
12557 return parse_arithmetic_or_logical_expr (
12558 tok
, std::move (left
), std::move (outer_attrs
),
12559 ArithmeticOrLogicalOperator::BITWISE_XOR
, restrictions
);
12561 // left shift expression - binary infix
12562 /*return parse_left_shift_expr (tok, std::move (left),
12563 std::move (outer_attrs), restrictions);*/
12564 return parse_arithmetic_or_logical_expr (
12565 tok
, std::move (left
), std::move (outer_attrs
),
12566 ArithmeticOrLogicalOperator::LEFT_SHIFT
, restrictions
);
12568 // right shift expression - binary infix
12569 /*return parse_right_shift_expr (tok, std::move (left),
12570 std::move (outer_attrs), restrictions);*/
12571 return parse_arithmetic_or_logical_expr (
12572 tok
, std::move (left
), std::move (outer_attrs
),
12573 ArithmeticOrLogicalOperator::RIGHT_SHIFT
, restrictions
);
12575 // equal to expression - binary infix (no associativity)
12576 /*return parse_binary_equal_expr (tok, std::move (left),
12577 std::move (outer_attrs),
12579 return parse_comparison_expr (tok
, std::move (left
),
12580 std::move (outer_attrs
),
12581 ComparisonOperator::EQUAL
, restrictions
);
12583 // not equal to expression - binary infix (no associativity)
12584 /*return parse_binary_not_equal_expr (tok, std::move (left),
12585 std::move (outer_attrs),
12587 return parse_comparison_expr (tok
, std::move (left
),
12588 std::move (outer_attrs
),
12589 ComparisonOperator::NOT_EQUAL
,
12592 // greater than expression - binary infix (no associativity)
12593 /*return parse_binary_greater_than_expr (tok, std::move (left),
12594 std::move (outer_attrs),
12596 return parse_comparison_expr (tok
, std::move (left
),
12597 std::move (outer_attrs
),
12598 ComparisonOperator::GREATER_THAN
,
12601 // less than expression - binary infix (no associativity)
12602 /*return parse_binary_less_than_expr (tok, std::move (left),
12603 std::move (outer_attrs),
12605 return parse_comparison_expr (tok
, std::move (left
),
12606 std::move (outer_attrs
),
12607 ComparisonOperator::LESS_THAN
,
12609 case GREATER_OR_EQUAL
:
12610 // greater than or equal to expression - binary infix (no associativity)
12611 /*return parse_binary_greater_equal_expr (tok, std::move (left),
12612 std::move (outer_attrs),
12614 return parse_comparison_expr (tok
, std::move (left
),
12615 std::move (outer_attrs
),
12616 ComparisonOperator::GREATER_OR_EQUAL
,
12618 case LESS_OR_EQUAL
:
12619 // less than or equal to expression - binary infix (no associativity)
12620 /*return parse_binary_less_equal_expr (tok, std::move (left),
12621 std::move (outer_attrs),
12623 return parse_comparison_expr (tok
, std::move (left
),
12624 std::move (outer_attrs
),
12625 ComparisonOperator::LESS_OR_EQUAL
,
12628 // lazy logical or expression - binary infix
12629 return parse_lazy_or_expr (tok
, std::move (left
), std::move (outer_attrs
),
12632 // lazy logical and expression - binary infix
12633 return parse_lazy_and_expr (tok
, std::move (left
),
12634 std::move (outer_attrs
), restrictions
);
12636 /* type cast expression - kind of binary infix (RHS is actually a
12638 return parse_type_cast_expr (tok
, std::move (left
),
12639 std::move (outer_attrs
), restrictions
);
12641 // assignment expression - binary infix (note right-to-left
12643 return parse_assig_expr (tok
, std::move (left
), std::move (outer_attrs
),
12646 /* plus-assignment expression - binary infix (note right-to-left
12647 * associativity) */
12648 /*return parse_plus_assig_expr (tok, std::move (left),
12649 std::move (outer_attrs), restrictions);*/
12650 return parse_compound_assignment_expr (tok
, std::move (left
),
12651 std::move (outer_attrs
),
12652 CompoundAssignmentOperator::ADD
,
12655 /* minus-assignment expression - binary infix (note right-to-left
12656 * associativity) */
12657 /*return parse_minus_assig_expr (tok, std::move (left),
12658 std::move (outer_attrs), restrictions);*/
12659 return parse_compound_assignment_expr (
12660 tok
, std::move (left
), std::move (outer_attrs
),
12661 CompoundAssignmentOperator::SUBTRACT
, restrictions
);
12663 /* multiply-assignment expression - binary infix (note right-to-left
12664 * associativity) */
12665 /*return parse_mult_assig_expr (tok, std::move (left),
12666 std::move (outer_attrs), restrictions);*/
12667 return parse_compound_assignment_expr (
12668 tok
, std::move (left
), std::move (outer_attrs
),
12669 CompoundAssignmentOperator::MULTIPLY
, restrictions
);
12671 /* division-assignment expression - binary infix (note right-to-left
12672 * associativity) */
12673 /*return parse_div_assig_expr (tok, std::move (left),
12674 std::move (outer_attrs), restrictions);*/
12675 return parse_compound_assignment_expr (tok
, std::move (left
),
12676 std::move (outer_attrs
),
12677 CompoundAssignmentOperator::DIVIDE
,
12680 /* modulo-assignment expression - binary infix (note right-to-left
12681 * associativity) */
12682 /*return parse_mod_assig_expr (tok, std::move (left),
12683 std::move (outer_attrs), restrictions);*/
12684 return parse_compound_assignment_expr (
12685 tok
, std::move (left
), std::move (outer_attrs
),
12686 CompoundAssignmentOperator::MODULUS
, restrictions
);
12688 /* bitwise and-assignment expression - binary infix (note right-to-left
12689 * associativity) */
12690 /*return parse_and_assig_expr (tok, std::move (left),
12691 std::move (outer_attrs), restrictions);*/
12692 return parse_compound_assignment_expr (
12693 tok
, std::move (left
), std::move (outer_attrs
),
12694 CompoundAssignmentOperator::BITWISE_AND
, restrictions
);
12696 /* bitwise or-assignment expression - binary infix (note right-to-left
12697 * associativity) */
12698 /*return parse_or_assig_expr (tok, std::move (left),
12699 std::move (outer_attrs), restrictions);*/
12700 return parse_compound_assignment_expr (
12701 tok
, std::move (left
), std::move (outer_attrs
),
12702 CompoundAssignmentOperator::BITWISE_OR
, restrictions
);
12704 /* bitwise xor-assignment expression - binary infix (note right-to-left
12705 * associativity) */
12706 /*return parse_xor_assig_expr (tok, std::move (left),
12707 std::move (outer_attrs), restrictions);*/
12708 return parse_compound_assignment_expr (
12709 tok
, std::move (left
), std::move (outer_attrs
),
12710 CompoundAssignmentOperator::BITWISE_XOR
, restrictions
);
12711 case LEFT_SHIFT_EQ
:
12712 /* left shift-assignment expression - binary infix (note right-to-left
12713 * associativity) */
12714 /*return parse_left_shift_assig_expr (tok, std::move (left),
12715 std::move (outer_attrs),
12717 return parse_compound_assignment_expr (
12718 tok
, std::move (left
), std::move (outer_attrs
),
12719 CompoundAssignmentOperator::LEFT_SHIFT
, restrictions
);
12720 case RIGHT_SHIFT_EQ
:
12721 /* right shift-assignment expression - binary infix (note right-to-left
12722 * associativity) */
12723 /*return parse_right_shift_assig_expr (tok, std::move (left),
12724 std::move (outer_attrs),
12726 return parse_compound_assignment_expr (
12727 tok
, std::move (left
), std::move (outer_attrs
),
12728 CompoundAssignmentOperator::RIGHT_SHIFT
, restrictions
);
12730 /* range exclusive expression - binary infix (no associativity)
12731 * either "range" or "range from" */
12732 return parse_led_range_exclusive_expr (tok
, std::move (left
),
12733 std::move (outer_attrs
),
12736 /* range inclusive expression - binary infix (no associativity)
12737 * unambiguously RangeInclusiveExpr */
12738 return parse_range_inclusive_expr (tok
, std::move (left
),
12739 std::move (outer_attrs
), restrictions
);
12740 case SCOPE_RESOLUTION
:
12741 // path expression - binary infix? FIXME should this even be parsed
12744 Error (tok
->get_locus (),
12745 "found scope resolution operator in left denotation "
12746 "function - this should probably be handled elsewhere"));
12750 /* field expression or method call - relies on parentheses after next
12751 * identifier or await if token after is "await" (unary postfix) or
12752 * tuple index if token after is a decimal int literal */
12754 const_TokenPtr next_tok
= lexer
.peek_token ();
12755 if (next_tok
->get_id () == IDENTIFIER
12756 && next_tok
->get_str () == Values::Keywords::AWAIT
)
12758 // await expression
12759 return parse_await_expr (tok
, std::move (left
),
12760 std::move (outer_attrs
));
12762 else if (next_tok
->get_id () == INT_LITERAL
)
12764 // tuple index expression - TODO check for decimal int literal
12765 return parse_tuple_index_expr (tok
, std::move (left
),
12766 std::move (outer_attrs
),
12769 else if (next_tok
->get_id () == FLOAT_LITERAL
)
12771 // Lexer has misidentified a tuple index as a float literal
12772 // eg: `(x, (y, z)).1.0` -> 1.0 has been identified as a float
12773 // literal. This means we should split it into three new separate
12774 // tokens, the first tuple index, the dot and the second tuple
12776 auto current_loc
= next_tok
->get_locus ();
12777 auto str
= next_tok
->get_str ();
12778 auto dot_pos
= str
.find (".");
12779 auto prefix
= str
.substr (0, dot_pos
);
12780 auto suffix
= str
.substr (dot_pos
+ 1);
12781 if (dot_pos
== str
.size () - 1)
12782 lexer
.split_current_token (
12783 {Token::make_int (current_loc
, std::move (prefix
),
12784 CORETYPE_PURE_DECIMAL
),
12785 Token::make (DOT
, current_loc
+ 1)});
12787 lexer
.split_current_token (
12788 {Token::make_int (current_loc
, std::move (prefix
),
12789 CORETYPE_PURE_DECIMAL
),
12790 Token::make (DOT
, current_loc
+ 1),
12791 Token::make_int (current_loc
+ 2, std::move (suffix
),
12792 CORETYPE_PURE_DECIMAL
)});
12793 return parse_tuple_index_expr (tok
, std::move (left
),
12794 std::move (outer_attrs
),
12797 else if (next_tok
->get_id () == IDENTIFIER
12798 && lexer
.peek_token (1)->get_id () != LEFT_PAREN
12799 && lexer
.peek_token (1)->get_id () != SCOPE_RESOLUTION
)
12801 /* field expression (or should be) - FIXME: scope resolution right
12802 * after identifier should always be method, I'm pretty sure */
12803 return parse_field_access_expr (tok
, std::move (left
),
12804 std::move (outer_attrs
),
12809 // method call (probably)
12810 return parse_method_call_expr (tok
, std::move (left
),
12811 std::move (outer_attrs
),
12816 // function call - method call is based on dot notation first
12817 return parse_function_call_expr (tok
, std::move (left
),
12818 std::move (outer_attrs
), restrictions
);
12820 // array or slice index expression (pseudo binary infix)
12821 return parse_index_expr (tok
, std::move (left
), std::move (outer_attrs
),
12823 case FLOAT_LITERAL
:
12824 /* HACK: get around lexer mis-identifying '.0' or '.1' or whatever as a
12825 * float literal - TODO does this happen anymore? It shouldn't. */
12826 return parse_tuple_index_expr_float (tok
, std::move (left
),
12827 std::move (outer_attrs
),
12830 add_error (Error (tok
->get_locus (),
12831 "found unexpected token %qs in left denotation",
12832 tok
->get_token_description ()));
12838 /* Returns the left binding power for the given ArithmeticOrLogicalExpr type.
12839 * TODO make constexpr? Would that even do anything useful? */
12840 inline binding_powers
12841 get_lbp_for_arithmetic_or_logical_expr (
12842 AST::ArithmeticOrLogicalExpr::ExprType expr_type
)
12846 case ArithmeticOrLogicalOperator::ADD
:
12848 case ArithmeticOrLogicalOperator::SUBTRACT
:
12850 case ArithmeticOrLogicalOperator::MULTIPLY
:
12852 case ArithmeticOrLogicalOperator::DIVIDE
:
12854 case ArithmeticOrLogicalOperator::MODULUS
:
12856 case ArithmeticOrLogicalOperator::BITWISE_AND
:
12858 case ArithmeticOrLogicalOperator::BITWISE_OR
:
12860 case ArithmeticOrLogicalOperator::BITWISE_XOR
:
12862 case ArithmeticOrLogicalOperator::LEFT_SHIFT
:
12863 return LBP_L_SHIFT
;
12864 case ArithmeticOrLogicalOperator::RIGHT_SHIFT
:
12865 return LBP_R_SHIFT
;
12867 // WTF? should not happen, this is an error
12868 rust_unreachable ();
12874 // Parses an arithmetic or logical expression (with Pratt parsing).
12875 template <typename ManagedTokenSource
>
12876 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
12877 Parser
<ManagedTokenSource
>::parse_arithmetic_or_logical_expr (
12878 const_TokenPtr
, std::unique_ptr
<AST::Expr
> left
, AST::AttrVec
,
12879 AST::ArithmeticOrLogicalExpr::ExprType expr_type
,
12880 ParseRestrictions restrictions
)
12882 // parse RHS (as tok has already been consumed in parse_expression)
12883 std::unique_ptr
<AST::Expr
> right
12884 = parse_expr (get_lbp_for_arithmetic_or_logical_expr (expr_type
),
12885 AST::AttrVec (), restrictions
);
12886 if (right
== nullptr)
12889 // TODO: check types. actually, do so during semantic analysis
12890 location_t locus
= left
->get_locus ();
12892 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
12893 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
12894 expr_type
, locus
));
12897 // Parses a binary addition expression (with Pratt parsing).
12898 template <typename ManagedTokenSource
>
12899 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
12900 Parser
<ManagedTokenSource
>::parse_binary_plus_expr (
12901 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
12902 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
12904 // parse RHS (as tok has already been consumed in parse_expression)
12905 std::unique_ptr
<AST::Expr
> right
12906 = parse_expr (LBP_PLUS
, AST::AttrVec (), restrictions
);
12907 if (right
== nullptr)
12910 // TODO: check types. actually, do so during semantic analysis
12911 location_t locus
= left
->get_locus ();
12913 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
12914 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
12915 ArithmeticOrLogicalOperator::ADD
, locus
));
12918 // Parses a binary subtraction expression (with Pratt parsing).
12919 template <typename ManagedTokenSource
>
12920 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
12921 Parser
<ManagedTokenSource
>::parse_binary_minus_expr (
12922 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
12923 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
12925 // parse RHS (as tok has already been consumed in parse_expression)
12926 std::unique_ptr
<AST::Expr
> right
12927 = parse_expr (LBP_MINUS
, AST::AttrVec (), restrictions
);
12928 if (right
== nullptr)
12931 // TODO: check types. actually, do so during semantic analysis
12932 location_t locus
= left
->get_locus ();
12934 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
12935 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
12936 ArithmeticOrLogicalOperator::SUBTRACT
,
12940 // Parses a binary multiplication expression (with Pratt parsing).
12941 template <typename ManagedTokenSource
>
12942 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
12943 Parser
<ManagedTokenSource
>::parse_binary_mult_expr (
12944 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
12945 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
12947 // parse RHS (as tok has already been consumed in parse_expression)
12948 std::unique_ptr
<AST::Expr
> right
12949 = parse_expr (LBP_MUL
, AST::AttrVec (), restrictions
);
12950 if (right
== nullptr)
12953 // TODO: check types. actually, do so during semantic analysis
12954 location_t locus
= left
->get_locus ();
12956 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
12957 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
12958 ArithmeticOrLogicalOperator::MULTIPLY
,
12962 // Parses a binary division expression (with Pratt parsing).
12963 template <typename ManagedTokenSource
>
12964 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
12965 Parser
<ManagedTokenSource
>::parse_binary_div_expr (
12966 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
12967 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
12969 // parse RHS (as tok has already been consumed in parse_expression)
12970 std::unique_ptr
<AST::Expr
> right
12971 = parse_expr (LBP_DIV
, AST::AttrVec (), restrictions
);
12972 if (right
== nullptr)
12975 // TODO: check types. actually, do so during semantic analysis
12976 location_t locus
= left
->get_locus ();
12978 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
12979 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
12980 ArithmeticOrLogicalOperator::DIVIDE
,
12984 // Parses a binary modulo expression (with Pratt parsing).
12985 template <typename ManagedTokenSource
>
12986 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
12987 Parser
<ManagedTokenSource
>::parse_binary_mod_expr (
12988 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
12989 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
12991 // parse RHS (as tok has already been consumed in parse_expression)
12992 std::unique_ptr
<AST::Expr
> right
12993 = parse_expr (LBP_MOD
, AST::AttrVec (), restrictions
);
12994 if (right
== nullptr)
12997 // TODO: check types. actually, do so during semantic analysis
12998 location_t locus
= left
->get_locus ();
13000 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13001 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13002 ArithmeticOrLogicalOperator::MODULUS
,
13006 /* Parses a binary bitwise (or eager logical) and expression (with Pratt
13008 template <typename ManagedTokenSource
>
13009 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13010 Parser
<ManagedTokenSource
>::parse_bitwise_and_expr (
13011 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13012 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13014 // parse RHS (as tok has already been consumed in parse_expression)
13015 std::unique_ptr
<AST::Expr
> right
13016 = parse_expr (LBP_AMP
, AST::AttrVec (), restrictions
);
13017 if (right
== nullptr)
13020 // TODO: check types. actually, do so during semantic analysis
13021 location_t locus
= left
->get_locus ();
13023 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13024 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13025 ArithmeticOrLogicalOperator::BITWISE_AND
,
13029 /* Parses a binary bitwise (or eager logical) or expression (with Pratt
13031 template <typename ManagedTokenSource
>
13032 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13033 Parser
<ManagedTokenSource
>::parse_bitwise_or_expr (
13034 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13035 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13037 // parse RHS (as tok has already been consumed in parse_expression)
13038 std::unique_ptr
<AST::Expr
> right
13039 = parse_expr (LBP_PIPE
, AST::AttrVec (), restrictions
);
13040 if (right
== nullptr)
13043 // TODO: check types. actually, do so during semantic analysis
13044 location_t locus
= left
->get_locus ();
13046 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13047 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13048 ArithmeticOrLogicalOperator::BITWISE_OR
,
13052 /* Parses a binary bitwise (or eager logical) xor expression (with Pratt
13054 template <typename ManagedTokenSource
>
13055 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13056 Parser
<ManagedTokenSource
>::parse_bitwise_xor_expr (
13057 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13058 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13060 // parse RHS (as tok has already been consumed in parse_expression)
13061 std::unique_ptr
<AST::Expr
> right
13062 = parse_expr (LBP_CARET
, AST::AttrVec (), restrictions
);
13063 if (right
== nullptr)
13066 // TODO: check types. actually, do so during semantic analysis
13067 location_t locus
= left
->get_locus ();
13069 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13070 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13071 ArithmeticOrLogicalOperator::BITWISE_XOR
,
13075 // Parses a binary left shift expression (with Pratt parsing).
13076 template <typename ManagedTokenSource
>
13077 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13078 Parser
<ManagedTokenSource
>::parse_left_shift_expr (
13079 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13080 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13082 // parse RHS (as tok has already been consumed in parse_expression)
13083 std::unique_ptr
<AST::Expr
> right
13084 = parse_expr (LBP_L_SHIFT
, AST::AttrVec (), restrictions
);
13085 if (right
== nullptr)
13088 // TODO: check types. actually, do so during semantic analysis
13089 location_t locus
= left
->get_locus ();
13091 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13092 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13093 ArithmeticOrLogicalOperator::LEFT_SHIFT
,
13097 // Parses a binary right shift expression (with Pratt parsing).
13098 template <typename ManagedTokenSource
>
13099 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13100 Parser
<ManagedTokenSource
>::parse_right_shift_expr (
13101 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13102 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13104 // parse RHS (as tok has already been consumed in parse_expression)
13105 std::unique_ptr
<AST::Expr
> right
13106 = parse_expr (LBP_R_SHIFT
, AST::AttrVec (), restrictions
);
13107 if (right
== nullptr)
13110 // TODO: check types. actually, do so during semantic analysis
13111 location_t locus
= left
->get_locus ();
13113 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13114 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13115 ArithmeticOrLogicalOperator::RIGHT_SHIFT
,
13119 /* Returns the left binding power for the given ComparisonExpr type.
13120 * TODO make constexpr? Would that even do anything useful? */
13121 inline binding_powers
13122 get_lbp_for_comparison_expr (AST::ComparisonExpr::ExprType expr_type
)
13126 case ComparisonOperator::EQUAL
:
13128 case ComparisonOperator::NOT_EQUAL
:
13129 return LBP_NOT_EQUAL
;
13130 case ComparisonOperator::GREATER_THAN
:
13131 return LBP_GREATER_THAN
;
13132 case ComparisonOperator::LESS_THAN
:
13133 return LBP_SMALLER_THAN
;
13134 case ComparisonOperator::GREATER_OR_EQUAL
:
13135 return LBP_GREATER_EQUAL
;
13136 case ComparisonOperator::LESS_OR_EQUAL
:
13137 return LBP_SMALLER_EQUAL
;
13139 // WTF? should not happen, this is an error
13140 rust_unreachable ();
13146 /* Parses a ComparisonExpr of given type and LBP. TODO find a way to only
13147 * specify one and have the other looked up - e.g. specify ExprType and
13148 * binding power is looked up? */
13149 template <typename ManagedTokenSource
>
13150 std::unique_ptr
<AST::ComparisonExpr
>
13151 Parser
<ManagedTokenSource
>::parse_comparison_expr (
13152 const_TokenPtr
, std::unique_ptr
<AST::Expr
> left
, AST::AttrVec
,
13153 AST::ComparisonExpr::ExprType expr_type
, ParseRestrictions restrictions
)
13155 // parse RHS (as tok has already been consumed in parse_expression)
13156 std::unique_ptr
<AST::Expr
> right
13157 = parse_expr (get_lbp_for_comparison_expr (expr_type
), AST::AttrVec (),
13159 if (right
== nullptr)
13162 // TODO: check types. actually, do so during semantic analysis
13163 location_t locus
= left
->get_locus ();
13165 return std::unique_ptr
<AST::ComparisonExpr
> (
13166 new AST::ComparisonExpr (std::move (left
), std::move (right
), expr_type
,
13170 // Parses a binary equal to expression (with Pratt parsing).
13171 template <typename ManagedTokenSource
>
13172 std::unique_ptr
<AST::ComparisonExpr
>
13173 Parser
<ManagedTokenSource
>::parse_binary_equal_expr (
13174 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13175 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13177 // parse RHS (as tok has already been consumed in parse_expression)
13178 std::unique_ptr
<AST::Expr
> right
13179 = parse_expr (LBP_EQUAL
, AST::AttrVec (), restrictions
);
13180 if (right
== nullptr)
13183 // TODO: check types. actually, do so during semantic analysis
13184 location_t locus
= left
->get_locus ();
13186 return std::unique_ptr
<AST::ComparisonExpr
> (
13187 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13188 ComparisonOperator::EQUAL
, locus
));
13191 // Parses a binary not equal to expression (with Pratt parsing).
13192 template <typename ManagedTokenSource
>
13193 std::unique_ptr
<AST::ComparisonExpr
>
13194 Parser
<ManagedTokenSource
>::parse_binary_not_equal_expr (
13195 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13196 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13198 // parse RHS (as tok has already been consumed in parse_expression)
13199 std::unique_ptr
<AST::Expr
> right
13200 = parse_expr (LBP_NOT_EQUAL
, AST::AttrVec (), restrictions
);
13201 if (right
== nullptr)
13204 // TODO: check types. actually, do so during semantic analysis
13205 location_t locus
= left
->get_locus ();
13207 return std::unique_ptr
<AST::ComparisonExpr
> (
13208 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13209 ComparisonOperator::NOT_EQUAL
, locus
));
13212 // Parses a binary greater than expression (with Pratt parsing).
13213 template <typename ManagedTokenSource
>
13214 std::unique_ptr
<AST::ComparisonExpr
>
13215 Parser
<ManagedTokenSource
>::parse_binary_greater_than_expr (
13216 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13217 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13219 // parse RHS (as tok has already been consumed in parse_expression)
13220 std::unique_ptr
<AST::Expr
> right
13221 = parse_expr (LBP_GREATER_THAN
, AST::AttrVec (), restrictions
);
13222 if (right
== nullptr)
13225 // TODO: check types. actually, do so during semantic analysis
13226 location_t locus
= left
->get_locus ();
13228 return std::unique_ptr
<AST::ComparisonExpr
> (
13229 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13230 ComparisonOperator::GREATER_THAN
, locus
));
13233 // Parses a binary less than expression (with Pratt parsing).
13234 template <typename ManagedTokenSource
>
13235 std::unique_ptr
<AST::ComparisonExpr
>
13236 Parser
<ManagedTokenSource
>::parse_binary_less_than_expr (
13237 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13238 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13240 // parse RHS (as tok has already been consumed in parse_expression)
13241 std::unique_ptr
<AST::Expr
> right
13242 = parse_expr (LBP_SMALLER_THAN
, AST::AttrVec (), restrictions
);
13243 if (right
== nullptr)
13246 // TODO: check types. actually, do so during semantic analysis
13247 location_t locus
= left
->get_locus ();
13249 return std::unique_ptr
<AST::ComparisonExpr
> (
13250 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13251 ComparisonOperator::LESS_THAN
, locus
));
13254 // Parses a binary greater than or equal to expression (with Pratt parsing).
13255 template <typename ManagedTokenSource
>
13256 std::unique_ptr
<AST::ComparisonExpr
>
13257 Parser
<ManagedTokenSource
>::parse_binary_greater_equal_expr (
13258 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13259 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13261 // parse RHS (as tok has already been consumed in parse_expression)
13262 std::unique_ptr
<AST::Expr
> right
13263 = parse_expr (LBP_GREATER_EQUAL
, AST::AttrVec (), restrictions
);
13264 if (right
== nullptr)
13267 // TODO: check types. actually, do so during semantic analysis
13268 location_t locus
= left
->get_locus ();
13270 return std::unique_ptr
<AST::ComparisonExpr
> (
13271 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13272 ComparisonOperator::GREATER_OR_EQUAL
, locus
));
13275 // Parses a binary less than or equal to expression (with Pratt parsing).
13276 template <typename ManagedTokenSource
>
13277 std::unique_ptr
<AST::ComparisonExpr
>
13278 Parser
<ManagedTokenSource
>::parse_binary_less_equal_expr (
13279 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13280 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13282 // parse RHS (as tok has already been consumed in parse_expression)
13283 std::unique_ptr
<AST::Expr
> right
13284 = parse_expr (LBP_SMALLER_EQUAL
, AST::AttrVec (), restrictions
);
13285 if (right
== nullptr)
13288 // TODO: check types. actually, do so during semantic analysis
13289 location_t locus
= left
->get_locus ();
13291 return std::unique_ptr
<AST::ComparisonExpr
> (
13292 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13293 ComparisonOperator::LESS_OR_EQUAL
, locus
));
13296 // Parses a binary lazy boolean or expression (with Pratt parsing).
13297 template <typename ManagedTokenSource
>
13298 std::unique_ptr
<AST::LazyBooleanExpr
>
13299 Parser
<ManagedTokenSource
>::parse_lazy_or_expr (
13300 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13301 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13303 // parse RHS (as tok has already been consumed in parse_expression)
13304 std::unique_ptr
<AST::Expr
> right
13305 = parse_expr (LBP_LOGICAL_OR
, AST::AttrVec (), restrictions
);
13306 if (right
== nullptr)
13309 // TODO: check types. actually, do so during semantic analysis
13310 location_t locus
= left
->get_locus ();
13312 return std::unique_ptr
<AST::LazyBooleanExpr
> (
13313 new AST::LazyBooleanExpr (std::move (left
), std::move (right
),
13314 LazyBooleanOperator::LOGICAL_OR
, locus
));
13317 // Parses a binary lazy boolean and expression (with Pratt parsing).
13318 template <typename ManagedTokenSource
>
13319 std::unique_ptr
<AST::LazyBooleanExpr
>
13320 Parser
<ManagedTokenSource
>::parse_lazy_and_expr (
13321 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13322 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13324 // parse RHS (as tok has already been consumed in parse_expression)
13325 std::unique_ptr
<AST::Expr
> right
13326 = parse_expr (LBP_LOGICAL_AND
, AST::AttrVec (), restrictions
);
13327 if (right
== nullptr)
13330 // TODO: check types. actually, do so during semantic analysis
13331 location_t locus
= left
->get_locus ();
13333 return std::unique_ptr
<AST::LazyBooleanExpr
> (
13334 new AST::LazyBooleanExpr (std::move (left
), std::move (right
),
13335 LazyBooleanOperator::LOGICAL_AND
, locus
));
13338 // Parses a pseudo-binary infix type cast expression (with Pratt parsing).
13339 template <typename ManagedTokenSource
>
13340 std::unique_ptr
<AST::TypeCastExpr
>
13341 Parser
<ManagedTokenSource
>::parse_type_cast_expr (
13342 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> expr_to_cast
,
13343 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
,
13344 ParseRestrictions restrictions ATTRIBUTE_UNUSED
)
13346 // parse RHS (as tok has already been consumed in parse_expression)
13347 std::unique_ptr
<AST::TypeNoBounds
> type
= parse_type_no_bounds ();
13348 if (type
== nullptr)
13350 // FIXME: how do I get precedence put in here?
13352 // TODO: check types. actually, do so during semantic analysis
13353 location_t locus
= expr_to_cast
->get_locus ();
13355 return std::unique_ptr
<AST::TypeCastExpr
> (
13356 new AST::TypeCastExpr (std::move (expr_to_cast
), std::move (type
), locus
));
13359 // Parses a binary assignment expression (with Pratt parsing).
13360 template <typename ManagedTokenSource
>
13361 std::unique_ptr
<AST::AssignmentExpr
>
13362 Parser
<ManagedTokenSource
>::parse_assig_expr (
13363 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13364 AST::AttrVec outer_attrs
, ParseRestrictions restrictions
)
13366 // parse RHS (as tok has already been consumed in parse_expression)
13367 std::unique_ptr
<AST::Expr
> right
13368 = parse_expr (LBP_ASSIG
- 1, AST::AttrVec (), restrictions
);
13369 if (right
== nullptr)
13371 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13373 // TODO: check types. actually, do so during semantic analysis
13374 location_t locus
= left
->get_locus ();
13376 return std::unique_ptr
<AST::AssignmentExpr
> (
13377 new AST::AssignmentExpr (std::move (left
), std::move (right
),
13378 std::move (outer_attrs
), locus
));
13381 /* Returns the left binding power for the given CompoundAssignmentExpr type.
13382 * TODO make constexpr? Would that even do anything useful? */
13383 inline binding_powers
13384 get_lbp_for_compound_assignment_expr (
13385 AST::CompoundAssignmentExpr::ExprType expr_type
)
13389 case CompoundAssignmentOperator::ADD
:
13391 case CompoundAssignmentOperator::SUBTRACT
:
13393 case CompoundAssignmentOperator::MULTIPLY
:
13395 case CompoundAssignmentOperator::DIVIDE
:
13397 case CompoundAssignmentOperator::MODULUS
:
13399 case CompoundAssignmentOperator::BITWISE_AND
:
13401 case CompoundAssignmentOperator::BITWISE_OR
:
13403 case CompoundAssignmentOperator::BITWISE_XOR
:
13405 case CompoundAssignmentOperator::LEFT_SHIFT
:
13406 return LBP_L_SHIFT
;
13407 case CompoundAssignmentOperator::RIGHT_SHIFT
:
13408 return LBP_R_SHIFT
;
13410 // WTF? should not happen, this is an error
13411 rust_unreachable ();
13417 // Parses a compound assignment expression (with Pratt parsing).
13418 template <typename ManagedTokenSource
>
13419 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13420 Parser
<ManagedTokenSource
>::parse_compound_assignment_expr (
13421 const_TokenPtr
, std::unique_ptr
<AST::Expr
> left
, AST::AttrVec
,
13422 AST::CompoundAssignmentExpr::ExprType expr_type
,
13423 ParseRestrictions restrictions
)
13425 // parse RHS (as tok has already been consumed in parse_expression)
13426 std::unique_ptr
<AST::Expr
> right
13427 = parse_expr (get_lbp_for_compound_assignment_expr (expr_type
) - 1,
13428 AST::AttrVec (), restrictions
);
13429 if (right
== nullptr)
13431 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13433 // TODO: check types. actually, do so during semantic analysis
13434 location_t locus
= left
->get_locus ();
13436 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13437 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13438 expr_type
, locus
));
13441 // Parses a binary add-assignment expression (with Pratt parsing).
13442 template <typename ManagedTokenSource
>
13443 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13444 Parser
<ManagedTokenSource
>::parse_plus_assig_expr (
13445 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13446 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13448 // parse RHS (as tok has already been consumed in parse_expression)
13449 std::unique_ptr
<AST::Expr
> right
13450 = parse_expr (LBP_PLUS_ASSIG
- 1, AST::AttrVec (), restrictions
);
13451 if (right
== nullptr)
13453 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13455 // TODO: check types. actually, do so during semantic analysis
13456 location_t locus
= left
->get_locus ();
13458 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13459 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13460 CompoundAssignmentOperator::ADD
, locus
));
13463 // Parses a binary minus-assignment expression (with Pratt parsing).
13464 template <typename ManagedTokenSource
>
13465 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13466 Parser
<ManagedTokenSource
>::parse_minus_assig_expr (
13467 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13468 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13470 // parse RHS (as tok has already been consumed in parse_expression)
13471 std::unique_ptr
<AST::Expr
> right
13472 = parse_expr (LBP_MINUS_ASSIG
- 1, AST::AttrVec (), restrictions
);
13473 if (right
== nullptr)
13475 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13477 // TODO: check types. actually, do so during semantic analysis
13478 location_t locus
= left
->get_locus ();
13480 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13481 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13482 CompoundAssignmentOperator::SUBTRACT
,
13486 // Parses a binary multiplication-assignment expression (with Pratt parsing).
13487 template <typename ManagedTokenSource
>
13488 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13489 Parser
<ManagedTokenSource
>::parse_mult_assig_expr (
13490 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13491 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13493 // parse RHS (as tok has already been consumed in parse_expression)
13494 std::unique_ptr
<AST::Expr
> right
13495 = parse_expr (LBP_MULT_ASSIG
- 1, AST::AttrVec (), restrictions
);
13496 if (right
== nullptr)
13498 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13500 // TODO: check types. actually, do so during semantic analysis
13501 location_t locus
= left
->get_locus ();
13503 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13504 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13505 CompoundAssignmentOperator::MULTIPLY
,
13509 // Parses a binary division-assignment expression (with Pratt parsing).
13510 template <typename ManagedTokenSource
>
13511 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13512 Parser
<ManagedTokenSource
>::parse_div_assig_expr (
13513 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13514 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13516 // parse RHS (as tok has already been consumed in parse_expression)
13517 std::unique_ptr
<AST::Expr
> right
13518 = parse_expr (LBP_DIV_ASSIG
- 1, AST::AttrVec (), restrictions
);
13519 if (right
== nullptr)
13521 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13523 // TODO: check types. actually, do so during semantic analysis
13524 location_t locus
= left
->get_locus ();
13526 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13527 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13528 CompoundAssignmentOperator::DIVIDE
,
13532 // Parses a binary modulo-assignment expression (with Pratt parsing).
13533 template <typename ManagedTokenSource
>
13534 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13535 Parser
<ManagedTokenSource
>::parse_mod_assig_expr (
13536 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13537 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13539 // parse RHS (as tok has already been consumed in parse_expression)
13540 std::unique_ptr
<AST::Expr
> right
13541 = parse_expr (LBP_MOD_ASSIG
- 1, AST::AttrVec (), restrictions
);
13542 if (right
== nullptr)
13544 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13546 // TODO: check types. actually, do so during semantic analysis
13547 location_t locus
= left
->get_locus ();
13549 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13550 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13551 CompoundAssignmentOperator::MODULUS
,
13555 // Parses a binary and-assignment expression (with Pratt parsing).
13556 template <typename ManagedTokenSource
>
13557 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13558 Parser
<ManagedTokenSource
>::parse_and_assig_expr (
13559 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13560 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13562 // parse RHS (as tok has already been consumed in parse_expression)
13563 std::unique_ptr
<AST::Expr
> right
13564 = parse_expr (LBP_AMP_ASSIG
- 1, AST::AttrVec (), restrictions
);
13565 if (right
== nullptr)
13567 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13569 // TODO: check types. actually, do so during semantic analysis
13570 location_t locus
= left
->get_locus ();
13572 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13573 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13574 CompoundAssignmentOperator::BITWISE_AND
,
13578 // Parses a binary or-assignment expression (with Pratt parsing).
13579 template <typename ManagedTokenSource
>
13580 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13581 Parser
<ManagedTokenSource
>::parse_or_assig_expr (
13582 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13583 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13585 // parse RHS (as tok has already been consumed in parse_expression)
13586 std::unique_ptr
<AST::Expr
> right
13587 = parse_expr (LBP_PIPE_ASSIG
- 1, AST::AttrVec (), restrictions
);
13588 if (right
== nullptr)
13590 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13592 // TODO: check types. actually, do so during semantic analysis
13593 location_t locus
= left
->get_locus ();
13595 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13596 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13597 CompoundAssignmentOperator::BITWISE_OR
,
13601 // Parses a binary xor-assignment expression (with Pratt parsing).
13602 template <typename ManagedTokenSource
>
13603 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13604 Parser
<ManagedTokenSource
>::parse_xor_assig_expr (
13605 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13606 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13608 // parse RHS (as tok has already been consumed in parse_expression)
13609 std::unique_ptr
<AST::Expr
> right
13610 = parse_expr (LBP_CARET_ASSIG
- 1, AST::AttrVec (), restrictions
);
13611 if (right
== nullptr)
13613 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13615 // TODO: check types. actually, do so during semantic analysis
13616 location_t locus
= left
->get_locus ();
13618 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13619 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13620 CompoundAssignmentOperator::BITWISE_XOR
,
13624 // Parses a binary left shift-assignment expression (with Pratt parsing).
13625 template <typename ManagedTokenSource
>
13626 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13627 Parser
<ManagedTokenSource
>::parse_left_shift_assig_expr (
13628 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13629 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13631 // parse RHS (as tok has already been consumed in parse_expression)
13632 std::unique_ptr
<AST::Expr
> right
13633 = parse_expr (LBP_L_SHIFT_ASSIG
- 1, AST::AttrVec (), restrictions
);
13634 if (right
== nullptr)
13636 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13638 // TODO: check types. actually, do so during semantic analysis
13639 location_t locus
= left
->get_locus ();
13641 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13642 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13643 CompoundAssignmentOperator::LEFT_SHIFT
,
13647 // Parses a binary right shift-assignment expression (with Pratt parsing).
13648 template <typename ManagedTokenSource
>
13649 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13650 Parser
<ManagedTokenSource
>::parse_right_shift_assig_expr (
13651 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13652 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13654 // parse RHS (as tok has already been consumed in parse_expression)
13655 std::unique_ptr
<AST::Expr
> right
13656 = parse_expr (LBP_R_SHIFT_ASSIG
- 1, AST::AttrVec (), restrictions
);
13657 if (right
== nullptr)
13659 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13661 // TODO: check types. actually, do so during semantic analysis
13662 location_t locus
= left
->get_locus ();
13664 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13665 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13666 CompoundAssignmentOperator::RIGHT_SHIFT
,
13670 // Parses a postfix unary await expression (with Pratt parsing).
13671 template <typename ManagedTokenSource
>
13672 std::unique_ptr
<AST::AwaitExpr
>
13673 Parser
<ManagedTokenSource
>::parse_await_expr (
13674 const_TokenPtr tok
, std::unique_ptr
<AST::Expr
> expr_to_await
,
13675 AST::AttrVec outer_attrs
)
13677 /* skip "await" identifier (as "." has already been consumed in
13678 * parse_expression) this assumes that the identifier was already identified
13680 if (!skip_token (IDENTIFIER
))
13682 Error
error (tok
->get_locus (), "failed to skip %<await%> in await expr "
13683 "- this is probably a deep issue");
13684 add_error (std::move (error
));
13690 // TODO: check inside async block in semantic analysis
13691 location_t locus
= expr_to_await
->get_locus ();
13693 return std::unique_ptr
<AST::AwaitExpr
> (
13694 new AST::AwaitExpr (std::move (expr_to_await
), std::move (outer_attrs
),
13698 /* Parses an exclusive range ('..') in left denotation position (i.e.
13699 * RangeFromExpr or RangeFromToExpr). */
13700 template <typename ManagedTokenSource
>
13701 std::unique_ptr
<AST::RangeExpr
>
13702 Parser
<ManagedTokenSource
>::parse_led_range_exclusive_expr (
13703 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13704 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13706 // FIXME: this probably parses expressions accidently or whatever
13707 // try parsing RHS (as tok has already been consumed in parse_expression)
13708 // Can be nullptr, in which case it is a RangeFromExpr, otherwise a
13709 // RangeFromToExpr.
13710 restrictions
.expr_can_be_null
= true;
13711 std::unique_ptr
<AST::Expr
> right
13712 = parse_expr (LBP_DOT_DOT
, AST::AttrVec (), restrictions
);
13714 location_t locus
= left
->get_locus ();
13716 if (right
== nullptr)
13719 return std::unique_ptr
<AST::RangeFromExpr
> (
13720 new AST::RangeFromExpr (std::move (left
), locus
));
13724 return std::unique_ptr
<AST::RangeFromToExpr
> (
13725 new AST::RangeFromToExpr (std::move (left
), std::move (right
), locus
));
13727 // FIXME: make non-associative
13730 /* Parses an exclusive range ('..') in null denotation position (i.e.
13731 * RangeToExpr or RangeFullExpr). */
13732 template <typename ManagedTokenSource
>
13733 std::unique_ptr
<AST::RangeExpr
>
13734 Parser
<ManagedTokenSource
>::parse_nud_range_exclusive_expr (
13735 const_TokenPtr tok
, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
)
13737 auto restrictions
= ParseRestrictions ();
13738 restrictions
.expr_can_be_null
= true;
13740 // FIXME: this probably parses expressions accidently or whatever
13741 // try parsing RHS (as tok has already been consumed in parse_expression)
13742 std::unique_ptr
<AST::Expr
> right
13743 = parse_expr (LBP_DOT_DOT
, AST::AttrVec (), restrictions
);
13745 location_t locus
= tok
->get_locus ();
13747 if (right
== nullptr)
13750 return std::unique_ptr
<AST::RangeFullExpr
> (
13751 new AST::RangeFullExpr (locus
));
13755 return std::unique_ptr
<AST::RangeToExpr
> (
13756 new AST::RangeToExpr (std::move (right
), locus
));
13758 // FIXME: make non-associative
13761 // Parses a full binary range inclusive expression.
13762 template <typename ManagedTokenSource
>
13763 std::unique_ptr
<AST::RangeFromToInclExpr
>
13764 Parser
<ManagedTokenSource
>::parse_range_inclusive_expr (
13765 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13766 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13768 // parse RHS (as tok has already been consumed in parse_expression)
13769 std::unique_ptr
<AST::Expr
> right
13770 = parse_expr (LBP_DOT_DOT_EQ
, AST::AttrVec (), restrictions
);
13771 if (right
== nullptr)
13773 // FIXME: make non-associative
13775 // TODO: check types. actually, do so during semantic analysis
13776 location_t locus
= left
->get_locus ();
13778 return std::unique_ptr
<AST::RangeFromToInclExpr
> (
13779 new AST::RangeFromToInclExpr (std::move (left
), std::move (right
), locus
));
13782 // Parses an inclusive range-to prefix unary expression.
13783 template <typename ManagedTokenSource
>
13784 std::unique_ptr
<AST::RangeToInclExpr
>
13785 Parser
<ManagedTokenSource
>::parse_range_to_inclusive_expr (
13786 const_TokenPtr tok
, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
)
13788 // parse RHS (as tok has already been consumed in parse_expression)
13789 std::unique_ptr
<AST::Expr
> right
= parse_expr (LBP_DOT_DOT_EQ
);
13790 if (right
== nullptr)
13792 // FIXME: make non-associative
13794 // TODO: check types. actually, do so during semantic analysis
13796 return std::unique_ptr
<AST::RangeToInclExpr
> (
13797 new AST::RangeToInclExpr (std::move (right
), tok
->get_locus ()));
13800 // Parses a pseudo-binary infix tuple index expression.
13801 template <typename ManagedTokenSource
>
13802 std::unique_ptr
<AST::TupleIndexExpr
>
13803 Parser
<ManagedTokenSource
>::parse_tuple_index_expr (
13804 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> tuple_expr
,
13805 AST::AttrVec outer_attrs
, ParseRestrictions restrictions ATTRIBUTE_UNUSED
)
13807 // parse int literal (as token already skipped)
13808 const_TokenPtr index_tok
= expect_token (INT_LITERAL
);
13809 if (index_tok
== nullptr)
13813 std::string index
= index_tok
->get_str ();
13815 // convert to integer
13816 if (!index_tok
->is_pure_decimal ())
13818 Error
error (index_tok
->get_locus (),
13819 "tuple index should be a pure decimal literal");
13820 add_error (std::move (error
));
13822 int index_int
= atoi (index
.c_str ());
13824 location_t locus
= tuple_expr
->get_locus ();
13826 return std::unique_ptr
<AST::TupleIndexExpr
> (
13827 new AST::TupleIndexExpr (std::move (tuple_expr
), index_int
,
13828 std::move (outer_attrs
), locus
));
13831 // Parses a pseudo-binary infix array (or slice) index expression.
13832 template <typename ManagedTokenSource
>
13833 std::unique_ptr
<AST::ArrayIndexExpr
>
13834 Parser
<ManagedTokenSource
>::parse_index_expr (
13835 const_TokenPtr
, std::unique_ptr
<AST::Expr
> array_expr
,
13836 AST::AttrVec outer_attrs
, ParseRestrictions
)
13838 // parse RHS (as tok has already been consumed in parse_expression)
13839 /*std::unique_ptr<AST::Expr> index_expr
13840 = parse_expr (LBP_ARRAY_REF, AST::AttrVec (),
13842 // TODO: conceptually, should treat [] as brackets, so just parse all expr
13843 std::unique_ptr
<AST::Expr
> index_expr
= parse_expr ();
13844 if (index_expr
== nullptr)
13847 // skip ']' at end of array
13848 if (!skip_token (RIGHT_SQUARE
))
13854 // TODO: check types. actually, do so during semantic analysis
13855 location_t locus
= array_expr
->get_locus ();
13857 return std::unique_ptr
<AST::ArrayIndexExpr
> (
13858 new AST::ArrayIndexExpr (std::move (array_expr
), std::move (index_expr
),
13859 std::move (outer_attrs
), locus
));
13862 // Parses a pseudo-binary infix struct field access expression.
13863 template <typename ManagedTokenSource
>
13864 std::unique_ptr
<AST::FieldAccessExpr
>
13865 Parser
<ManagedTokenSource
>::parse_field_access_expr (
13866 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> struct_expr
,
13867 AST::AttrVec outer_attrs
, ParseRestrictions restrictions ATTRIBUTE_UNUSED
)
13869 /* get field name identifier (assume that this is a field access expr and
13870 * not await, for instance) */
13871 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
13872 if (ident_tok
== nullptr)
13875 Identifier ident
{ident_tok
};
13877 location_t locus
= struct_expr
->get_locus ();
13879 // TODO: check types. actually, do so during semantic analysis
13880 return std::unique_ptr
<AST::FieldAccessExpr
> (
13881 new AST::FieldAccessExpr (std::move (struct_expr
), std::move (ident
),
13882 std::move (outer_attrs
), locus
));
13885 // Parses a pseudo-binary infix method call expression.
13886 template <typename ManagedTokenSource
>
13887 std::unique_ptr
<AST::MethodCallExpr
>
13888 Parser
<ManagedTokenSource
>::parse_method_call_expr (
13889 const_TokenPtr tok
, std::unique_ptr
<AST::Expr
> receiver_expr
,
13890 AST::AttrVec outer_attrs
, ParseRestrictions
)
13892 // parse path expr segment
13893 AST::PathExprSegment segment
= parse_path_expr_segment ();
13894 if (segment
.is_error ())
13896 Error
error (tok
->get_locus (),
13897 "failed to parse path expr segment of method call expr");
13898 add_error (std::move (error
));
13903 // skip left parentheses
13904 if (!skip_token (LEFT_PAREN
))
13909 // parse method params (if they exist)
13910 std::vector
<std::unique_ptr
<AST::Expr
>> params
;
13912 const_TokenPtr t
= lexer
.peek_token ();
13913 while (t
->get_id () != RIGHT_PAREN
)
13915 std::unique_ptr
<AST::Expr
> param
= parse_expr ();
13916 if (param
== nullptr)
13918 Error
error (t
->get_locus (),
13919 "failed to parse method param in method call");
13920 add_error (std::move (error
));
13924 params
.push_back (std::move (param
));
13926 if (lexer
.peek_token ()->get_id () != COMMA
)
13929 lexer
.skip_token ();
13930 t
= lexer
.peek_token ();
13933 // skip right paren
13934 if (!skip_token (RIGHT_PAREN
))
13939 // TODO: check types. actually do so in semantic analysis pass.
13940 location_t locus
= receiver_expr
->get_locus ();
13942 return std::unique_ptr
<AST::MethodCallExpr
> (
13943 new AST::MethodCallExpr (std::move (receiver_expr
), std::move (segment
),
13944 std::move (params
), std::move (outer_attrs
),
13948 // Parses a pseudo-binary infix function call expression.
13949 template <typename ManagedTokenSource
>
13950 std::unique_ptr
<AST::CallExpr
>
13951 Parser
<ManagedTokenSource
>::parse_function_call_expr (
13952 const_TokenPtr
, std::unique_ptr
<AST::Expr
> function_expr
,
13953 AST::AttrVec outer_attrs
, ParseRestrictions
)
13955 // parse function params (if they exist)
13956 std::vector
<std::unique_ptr
<AST::Expr
>> params
;
13958 const_TokenPtr t
= lexer
.peek_token ();
13959 while (t
->get_id () != RIGHT_PAREN
)
13961 std::unique_ptr
<AST::Expr
> param
= parse_expr ();
13962 if (param
== nullptr)
13964 Error
error (t
->get_locus (),
13965 "failed to parse function param in function call");
13966 add_error (std::move (error
));
13970 params
.push_back (std::move (param
));
13972 if (lexer
.peek_token ()->get_id () != COMMA
)
13975 lexer
.skip_token ();
13976 t
= lexer
.peek_token ();
13979 // skip ')' at end of param list
13980 if (!skip_token (RIGHT_PAREN
))
13986 // TODO: check types. actually, do so during semantic analysis
13987 location_t locus
= function_expr
->get_locus ();
13989 return std::unique_ptr
<AST::CallExpr
> (
13990 new AST::CallExpr (std::move (function_expr
), std::move (params
),
13991 std::move (outer_attrs
), locus
));
13994 /* Parses a macro invocation with a path in expression already parsed (but not
13996 template <typename ManagedTokenSource
>
13997 std::unique_ptr
<AST::MacroInvocation
>
13998 Parser
<ManagedTokenSource
>::parse_macro_invocation_partial (
13999 AST::PathInExpression path
, AST::AttrVec outer_attrs
,
14000 ParseRestrictions restrictions
)
14002 // macro invocation
14003 if (!skip_token (EXCLAM
))
14008 // convert PathInExpression to SimplePath - if this isn't possible, error
14009 AST::SimplePath converted_path
= path
.as_simple_path ();
14010 if (converted_path
.is_empty ())
14012 Error
error (lexer
.peek_token ()->get_locus (),
14013 "failed to parse simple path in macro invocation");
14014 add_error (std::move (error
));
14019 AST::DelimTokenTree tok_tree
= parse_delim_token_tree ();
14021 rust_debug ("successfully parsed macro invocation (via partial)");
14023 location_t macro_locus
= converted_path
.get_locus ();
14025 return AST::MacroInvocation::Regular (
14026 AST::MacroInvocData (std::move (converted_path
), std::move (tok_tree
)),
14027 std::move (outer_attrs
), macro_locus
);
14030 /* Parses a struct expr struct with a path in expression already parsed (but
14033 template <typename ManagedTokenSource
>
14034 std::unique_ptr
<AST::StructExprStruct
>
14035 Parser
<ManagedTokenSource
>::parse_struct_expr_struct_partial (
14036 AST::PathInExpression path
, AST::AttrVec outer_attrs
)
14038 // assume struct expr struct (as struct-enum disambiguation requires name
14039 // lookup) again, make statement if final ';'
14040 if (!skip_token (LEFT_CURLY
))
14045 // parse inner attributes
14046 AST::AttrVec inner_attrs
= parse_inner_attributes ();
14048 // branch based on next token
14049 const_TokenPtr t
= lexer
.peek_token ();
14050 location_t path_locus
= path
.get_locus ();
14051 switch (t
->get_id ())
14054 // struct with no body
14055 lexer
.skip_token ();
14057 return std::unique_ptr
<AST::StructExprStruct
> (
14058 new AST::StructExprStruct (std::move (path
), std::move (inner_attrs
),
14059 std::move (outer_attrs
), path_locus
));
14061 /* technically this would give a struct base-only struct, but this
14062 * algorithm should work too. As such, AST type not happening. */
14065 case INT_LITERAL
: {
14066 // struct with struct expr fields
14068 // parse struct expr fields
14069 std::vector
<std::unique_ptr
<AST::StructExprField
>> fields
;
14071 while (t
->get_id () != RIGHT_CURLY
&& t
->get_id () != DOT_DOT
)
14073 std::unique_ptr
<AST::StructExprField
> field
14074 = parse_struct_expr_field ();
14075 if (field
== nullptr)
14077 Error
error (t
->get_locus (),
14078 "failed to parse struct (or enum) expr field");
14079 add_error (std::move (error
));
14085 rust_debug ("struct/enum expr field validated to not be null");
14087 fields
.push_back (std::move (field
));
14090 rust_debug ("struct/enum expr field pushed back");
14092 if (lexer
.peek_token ()->get_id () != COMMA
)
14095 rust_debug ("lack of comma detected in struct/enum expr "
14099 lexer
.skip_token ();
14102 rust_debug ("struct/enum expr fields comma skipped ");
14104 t
= lexer
.peek_token ();
14108 rust_debug ("struct/enum expr about to parse struct base ");
14110 // parse struct base if it exists
14111 AST::StructBase struct_base
= AST::StructBase::error ();
14112 if (lexer
.peek_token ()->get_id () == DOT_DOT
)
14114 location_t dot_dot_location
= lexer
.peek_token ()->get_locus ();
14115 lexer
.skip_token ();
14117 // parse required struct base expr
14118 std::unique_ptr
<AST::Expr
> base_expr
= parse_expr ();
14119 if (base_expr
== nullptr)
14121 Error
error (lexer
.peek_token ()->get_locus (),
14122 "failed to parse struct base expression in struct "
14124 add_error (std::move (error
));
14130 rust_debug ("struct/enum expr - parsed and validated base expr");
14133 = AST::StructBase (std::move (base_expr
), dot_dot_location
);
14136 rust_debug ("assigned struct base to new struct base ");
14139 if (!skip_token (RIGHT_CURLY
))
14146 "struct/enum expr skipped right curly - done and ready to return");
14148 return std::unique_ptr
<AST::StructExprStructFields
> (
14149 new AST::StructExprStructFields (std::move (path
), std::move (fields
),
14150 path_locus
, std::move (struct_base
),
14151 std::move (inner_attrs
),
14152 std::move (outer_attrs
)));
14156 Error (t
->get_locus (),
14157 "unrecognised token %qs in struct (or enum) expression - "
14158 "expected %<}%>, identifier, integer literal, or %<..%>",
14159 t
->get_token_description ()));
14165 /* Parses a struct expr tuple with a path in expression already parsed (but
14168 * FIXME: this currently outputs a call expr, as they cannot be disambiguated.
14169 * A better solution would be to just get this to call that function directly.
14171 template <typename ManagedTokenSource
>
14172 std::unique_ptr
<AST::CallExpr
>
14173 Parser
<ManagedTokenSource
>::parse_struct_expr_tuple_partial (
14174 AST::PathInExpression path
, AST::AttrVec outer_attrs
)
14176 if (!skip_token (LEFT_PAREN
))
14181 AST::AttrVec inner_attrs
= parse_inner_attributes ();
14183 std::vector
<std::unique_ptr
<AST::Expr
>> exprs
;
14185 const_TokenPtr t
= lexer
.peek_token ();
14186 while (t
->get_id () != RIGHT_PAREN
)
14188 // parse expression (required)
14189 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
14190 if (expr
== nullptr)
14192 Error
error (t
->get_locus (), "failed to parse expression in "
14193 "struct (or enum) expression tuple");
14194 add_error (std::move (error
));
14198 exprs
.push_back (std::move (expr
));
14200 if (lexer
.peek_token ()->get_id () != COMMA
)
14203 lexer
.skip_token ();
14205 t
= lexer
.peek_token ();
14208 if (!skip_token (RIGHT_PAREN
))
14213 location_t path_locus
= path
.get_locus ();
14215 auto pathExpr
= std::unique_ptr
<AST::PathInExpression
> (
14216 new AST::PathInExpression (std::move (path
)));
14218 return std::unique_ptr
<AST::CallExpr
> (
14219 new AST::CallExpr (std::move (pathExpr
), std::move (exprs
),
14220 std::move (outer_attrs
), path_locus
));
14223 /* Parses a path in expression with the first token passed as a parameter (as
14224 * it is skipped in token stream). Note that this only parses segment-first
14225 * paths, not global ones. */
14226 template <typename ManagedTokenSource
>
14227 AST::PathInExpression
14228 Parser
<ManagedTokenSource
>::parse_path_in_expression_pratt (const_TokenPtr tok
)
14230 // HACK-y way of making up for pratt-parsing consuming first token
14233 rust_debug ("current peek token when starting path pratt parse: '%s'",
14234 lexer
.peek_token ()->get_token_description ());
14236 // create segment vector
14237 std::vector
<AST::PathExprSegment
> segments
;
14239 std::string initial_str
;
14241 switch (tok
->get_id ())
14244 initial_str
= tok
->get_str ();
14247 initial_str
= Values::Keywords::SUPER
;
14250 initial_str
= Values::Keywords::SELF
;
14253 initial_str
= Values::Keywords::SELF_ALIAS
;
14256 initial_str
= Values::Keywords::CRATE
;
14259 if (lexer
.peek_token ()->get_id () == CRATE
)
14261 initial_str
= "$crate";
14264 gcc_fallthrough ();
14266 add_error (Error (tok
->get_locus (),
14267 "unrecognised token %qs in path in expression",
14268 tok
->get_token_description ()));
14270 return AST::PathInExpression::create_error ();
14273 // parse required initial segment
14274 AST::PathExprSegment
initial_segment (initial_str
, tok
->get_locus ());
14275 // parse generic args (and turbofish), if they exist
14276 /* use lookahead to determine if they actually exist (don't want to
14277 * accidently parse over next ident segment) */
14278 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
14279 && lexer
.peek_token (1)->get_id () == LEFT_ANGLE
)
14281 // skip scope resolution
14282 lexer
.skip_token ();
14284 AST::GenericArgs generic_args
= parse_path_generic_args ();
14287 = AST::PathExprSegment (AST::PathIdentSegment (initial_str
,
14288 tok
->get_locus ()),
14289 tok
->get_locus (), std::move (generic_args
));
14291 if (initial_segment
.is_error ())
14293 // skip after somewhere?
14294 // don't necessarily throw error but yeah
14297 rust_debug ("initial segment is error - returning null");
14299 return AST::PathInExpression::create_error ();
14301 segments
.push_back (std::move (initial_segment
));
14303 // parse optional segments (as long as scope resolution operator exists)
14304 const_TokenPtr t
= lexer
.peek_token ();
14305 while (t
->get_id () == SCOPE_RESOLUTION
)
14307 // skip scope resolution operator
14308 lexer
.skip_token ();
14310 // parse the actual segment - it is an error if it doesn't exist now
14311 AST::PathExprSegment segment
= parse_path_expr_segment ();
14312 if (segment
.is_error ())
14314 // skip after somewhere?
14315 Error
error (t
->get_locus (),
14316 "could not parse path expression segment");
14317 add_error (std::move (error
));
14319 return AST::PathInExpression::create_error ();
14322 segments
.push_back (std::move (segment
));
14324 t
= lexer
.peek_token ();
14329 "current token (just about to return path to null denotation): '%s'",
14330 lexer
.peek_token ()->get_token_description ());
14332 return AST::PathInExpression (std::move (segments
), {}, tok
->get_locus (),
14336 // Parses a closure expression with pratt parsing (from null denotation).
14337 template <typename ManagedTokenSource
>
14338 std::unique_ptr
<AST::ClosureExpr
>
14339 Parser
<ManagedTokenSource
>::parse_closure_expr_pratt (const_TokenPtr tok
,
14340 AST::AttrVec outer_attrs
)
14342 // TODO: does this need pratt parsing (for precedence)? probably not, but
14344 location_t locus
= tok
->get_locus ();
14345 bool has_move
= false;
14346 if (tok
->get_id () == MOVE
)
14349 tok
= lexer
.peek_token ();
14350 lexer
.skip_token ();
14351 // skip token and reassign
14354 // handle parameter list
14355 std::vector
<AST::ClosureParam
> params
;
14357 switch (tok
->get_id ())
14360 // no parameters, don't skip token
14363 // actually may have parameters
14364 // don't skip token
14365 const_TokenPtr t
= lexer
.peek_token ();
14366 while (t
->get_id () != PIPE
)
14368 AST::ClosureParam param
= parse_closure_param ();
14369 if (param
.is_error ())
14371 // TODO is this really an error?
14372 Error
error (t
->get_locus (), "could not parse closure param");
14373 add_error (std::move (error
));
14377 params
.push_back (std::move (param
));
14379 if (lexer
.peek_token ()->get_id () != COMMA
)
14381 if (lexer
.peek_token ()->get_id () == OR
)
14382 lexer
.split_current_token (PIPE
, PIPE
);
14383 // not an error but means param list is done
14387 lexer
.skip_token ();
14389 if (lexer
.peek_token ()->get_id () == OR
)
14390 lexer
.split_current_token (PIPE
, PIPE
);
14392 t
= lexer
.peek_token ();
14395 if (!skip_token (PIPE
))
14402 add_error (Error (tok
->get_locus (),
14403 "unexpected token %qs in closure expression - expected "
14405 tok
->get_token_description ()));
14411 // again branch based on next token
14412 tok
= lexer
.peek_token ();
14413 if (tok
->get_id () == RETURN_TYPE
)
14415 // must be return type closure with block expr
14417 // skip "return type" token
14418 lexer
.skip_token ();
14420 // parse actual type, which is required
14421 std::unique_ptr
<AST::TypeNoBounds
> type
= parse_type_no_bounds ();
14422 if (type
== nullptr)
14425 Error
error (tok
->get_locus (), "failed to parse type for closure");
14426 add_error (std::move (error
));
14432 // parse block expr, which is required
14433 std::unique_ptr
<AST::BlockExpr
> block
= parse_block_expr ();
14434 if (block
== nullptr)
14437 Error
error (lexer
.peek_token ()->get_locus (),
14438 "failed to parse block expr in closure");
14439 add_error (std::move (error
));
14445 return std::unique_ptr
<AST::ClosureExprInnerTyped
> (
14446 new AST::ClosureExprInnerTyped (std::move (type
), std::move (block
),
14447 std::move (params
), locus
, has_move
,
14448 std::move (outer_attrs
)));
14452 // must be expr-only closure
14454 // parse expr, which is required
14455 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
14456 if (expr
== nullptr)
14458 Error
error (tok
->get_locus (),
14459 "failed to parse expression in closure");
14460 add_error (std::move (error
));
14466 return std::unique_ptr
<AST::ClosureExprInner
> (
14467 new AST::ClosureExprInner (std::move (expr
), std::move (params
), locus
,
14468 has_move
, std::move (outer_attrs
)));
14472 /* Parses a tuple index expression (pratt-parsed) from a 'float' token as a
14473 * result of lexer misidentification. */
14474 template <typename ManagedTokenSource
>
14475 std::unique_ptr
<AST::TupleIndexExpr
>
14476 Parser
<ManagedTokenSource
>::parse_tuple_index_expr_float (
14477 const_TokenPtr tok
, std::unique_ptr
<AST::Expr
> tuple_expr
,
14478 AST::AttrVec outer_attrs
, ParseRestrictions restrictions ATTRIBUTE_UNUSED
)
14480 // only works on float literals
14481 if (tok
->get_id () != FLOAT_LITERAL
)
14485 rust_debug ("exact string form of float: '%s'", tok
->get_str ().c_str ());
14487 // get float string and remove dot and initial 0
14488 std::string index_str
= tok
->get_str ();
14489 index_str
.erase (index_str
.begin ());
14491 // get int from string
14492 int index
= atoi (index_str
.c_str ());
14494 location_t locus
= tuple_expr
->get_locus ();
14496 return std::unique_ptr
<AST::TupleIndexExpr
> (
14497 new AST::TupleIndexExpr (std::move (tuple_expr
), index
,
14498 std::move (outer_attrs
), locus
));
14501 // Returns true if the next token is END, ELSE, or EOF;
14502 template <typename ManagedTokenSource
>
14504 Parser
<ManagedTokenSource
>::done_end_or_else ()
14506 const_TokenPtr t
= lexer
.peek_token ();
14507 return (t
->get_id () == RIGHT_CURLY
|| t
->get_id () == ELSE
14508 || t
->get_id () == END_OF_FILE
);
14511 // Returns true if the next token is END or EOF.
14512 template <typename ManagedTokenSource
>
14514 Parser
<ManagedTokenSource
>::done_end ()
14516 const_TokenPtr t
= lexer
.peek_token ();
14517 return (t
->get_id () == RIGHT_CURLY
|| t
->get_id () == END_OF_FILE
);
14519 } // namespace Rust