1 // Copyright (C) 2020-2023 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 #define INCLUDE_ALGORITHM
26 #include "rust-diagnostics.h"
27 #include "rust-make-unique.h"
30 // Left binding powers of operations.
42 LBP_FUNCTION_CALL
= 80,
43 LBP_ARRAY_REF
= LBP_FUNCTION_CALL
,
45 LBP_QUESTION_MARK
= 75, // unary postfix - counts as left
47 LBP_UNARY_PLUS
= 70, // Used only when the null denotation is +
48 LBP_UNARY_MINUS
= LBP_UNARY_PLUS
, // Used only when the null denotation is -
49 LBP_UNARY_ASTERISK
= LBP_UNARY_PLUS
, // deref operator - unary prefix
50 LBP_UNARY_EXCLAM
= LBP_UNARY_PLUS
,
51 LBP_UNARY_AMP
= LBP_UNARY_PLUS
,
52 LBP_UNARY_AMP_MUT
= LBP_UNARY_PLUS
,
64 LBP_R_SHIFT
= LBP_L_SHIFT
,
73 LBP_NOT_EQUAL
= LBP_EQUAL
,
74 LBP_SMALLER_THAN
= LBP_EQUAL
,
75 LBP_SMALLER_EQUAL
= LBP_EQUAL
,
76 LBP_GREATER_THAN
= LBP_EQUAL
,
77 LBP_GREATER_EQUAL
= LBP_EQUAL
,
84 LBP_DOT_DOT_EQ
= LBP_DOT_DOT
,
86 // TODO: note all these assig operators are RIGHT associative!
88 LBP_PLUS_ASSIG
= LBP_ASSIG
,
89 LBP_MINUS_ASSIG
= LBP_ASSIG
,
90 LBP_MULT_ASSIG
= LBP_ASSIG
,
91 LBP_DIV_ASSIG
= LBP_ASSIG
,
92 LBP_MOD_ASSIG
= LBP_ASSIG
,
93 LBP_AMP_ASSIG
= LBP_ASSIG
,
94 LBP_PIPE_ASSIG
= LBP_ASSIG
,
95 LBP_CARET_ASSIG
= LBP_ASSIG
,
96 LBP_L_SHIFT_ASSIG
= LBP_ASSIG
,
97 LBP_R_SHIFT_ASSIG
= LBP_ASSIG
,
99 // return, break, and closures as lowest priority?
101 LBP_BREAK
= LBP_RETURN
,
102 LBP_CLOSURE
= LBP_RETURN
, // unary prefix operators
108 // used for break, continue, return, and yield
110 // used for range (although weird comment in rustc about this)
112 // used for binary operators mentioned below - also cast, colon (type),
114 PREC_BINOP
= FROM_ASSOC_OP
,
115 // used for box, address_of, let, unary (again, weird comment on let)
117 // used for await, call, method call, field, index, try,
118 // inline asm, macro invocation
120 // used for array, repeat, tuple, literal, path, paren, if,
121 // while, for, 'loop', match, block, try block, async, struct
123 PREC_FORCE_PAREN
= 100,
130 /* Returns whether the token can start a type (i.e. there is a valid type
131 * beginning with the token). */
133 can_tok_start_type (TokenId id
)
150 case SCOPE_RESOLUTION
:
167 /* Returns whether the token id is (or is likely to be) a right angle bracket.
168 * i.e. '>', '>>', '>=' and '>>=' tokens. */
170 is_right_angle_tok (TokenId id
)
176 case GREATER_OR_EQUAL
:
184 /* HACK-y special handling for skipping a right angle token at the end of
186 * Currently, this replaces the "current token" with one that is identical
187 * except has the leading '>' removed (e.g. '>>' becomes '>'). This is bad
188 * for several reasons - it modifies the token stream to something that
189 * actually doesn't make syntactic sense, it may not worked if the token
190 * has already been skipped, etc. It was done because it would not
191 * actually require inserting new items into the token stream (which I
192 * thought would take more work to not mess up) and because I wasn't sure
193 * if the "already seen right angle" flag in the parser would work
195 * Those two other approaches listed are in my opinion actually better
196 * long-term - insertion is probably best as it reflects syntactically
197 * what occurs. On the other hand, I need to do a code audit to make sure
198 * that insertion doesn't mess anything up. So that's a FIXME. */
199 template <typename ManagedTokenSource
>
201 Parser
<ManagedTokenSource
>::skip_generics_right_angle ()
203 /* OK, new great idea. Have a lexer method called
204 * "split_current_token(TokenType newLeft, TokenType newRight)", which is
205 * called here with whatever arguments are appropriate. That lexer method
206 * handles "replacing" the current token with the "newLeft" and "inserting"
207 * the next token with the "newRight" (and creating a location, etc. for it)
210 /* HACK: special handling for right shift '>>', greater or equal '>=', and
211 * right shift assig */
213 const_TokenPtr tok
= lexer
.peek_token ();
214 switch (tok
->get_id ())
217 // this is good - skip token
221 // new implementation that should be better
222 lexer
.split_current_token (RIGHT_ANGLE
, RIGHT_ANGLE
);
226 case GREATER_OR_EQUAL
: {
227 // new implementation that should be better
228 lexer
.split_current_token (RIGHT_ANGLE
, EQUAL
);
232 case RIGHT_SHIFT_EQ
: {
233 // new implementation that should be better
234 lexer
.split_current_token (RIGHT_ANGLE
, GREATER_OR_EQUAL
);
239 add_error (Error (tok
->get_locus (),
240 "expected %<>%> at end of generic argument - found %qs",
241 tok
->get_token_description ()));
246 /* Gets left binding power for specified token.
247 * Not suitable for use at the moment or possibly ever because binding power
248 * cannot be purely determined from operator token with Rust grammar - e.g.
249 * method call and field access have
250 * different left binding powers but the same operator token. */
251 template <typename ManagedTokenSource
>
253 Parser
<ManagedTokenSource
>::left_binding_power (const_TokenPtr token
)
255 // HACK: called with "peek_token()", so lookahead is "peek_token(1)"
256 switch (token
->get_id ())
258 /* TODO: issue here - distinguish between method calls and field access
259 * somehow? Also would have to distinguish between paths and function
260 * calls (:: operator), maybe more stuff. */
261 /* Current plan for tackling LBP - don't do it based on token, use
262 * lookahead. Or alternatively, only use Pratt parsing for OperatorExpr
263 * and handle other expressions without it. rustc only considers
264 * arithmetic, logical/relational, 'as',
265 * '?=', ranges, colons, and assignment to have operator precedence and
266 * associativity rules applicable. It then has
267 * a separate "ExprPrecedence" that also includes binary operators. */
269 // TODO: handle operator overloading - have a function replace the
275 case SCOPE_RESOLUTION
:
277 "possible error - looked up LBP of scope resolution operator. should "
278 "be handled elsewhere.");
281 /* Resolved by lookahead HACK that should work with current code. If next
282 * token is identifier and token after that isn't parenthesised expression
283 * list, it is a field reference. */
285 if (lexer
.peek_token (1)->get_id () == IDENTIFIER
286 && lexer
.peek_token (2)->get_id () != LEFT_PAREN
)
288 return LBP_FIELD_EXPR
;
290 return LBP_METHOD_CALL
;
293 return LBP_FUNCTION_CALL
;
296 return LBP_ARRAY_REF
;
298 // postfix question mark (i.e. error propagation expression)
300 return LBP_QUESTION_MARK
;
337 return LBP_NOT_EQUAL
;
339 return LBP_GREATER_THAN
;
340 case GREATER_OR_EQUAL
:
341 return LBP_GREATER_EQUAL
;
343 return LBP_SMALLER_THAN
;
345 return LBP_SMALLER_EQUAL
;
348 return LBP_LOGICAL_AND
;
351 return LBP_LOGICAL_OR
;
357 return LBP_DOT_DOT_EQ
;
362 return LBP_PLUS_ASSIG
;
364 return LBP_MINUS_ASSIG
;
366 return LBP_MULT_ASSIG
;
368 return LBP_DIV_ASSIG
;
370 return LBP_MOD_ASSIG
;
372 return LBP_AMP_ASSIG
;
374 return LBP_PIPE_ASSIG
;
376 return LBP_CARET_ASSIG
;
378 return LBP_L_SHIFT_ASSIG
;
380 return LBP_R_SHIFT_ASSIG
;
382 /* HACK: float literal due to lexer misidentifying a dot then an integer as
385 return LBP_FIELD_EXPR
;
386 // field expr is same as tuple expr in precedence, i imagine
387 // TODO: is this needed anymore? lexer shouldn't do that anymore
389 // anything that can't appear in an infix position is given lowest priority
395 // Returns true when current token is EOF.
396 template <typename ManagedTokenSource
>
398 Parser
<ManagedTokenSource
>::done_end_of_file ()
400 return lexer
.peek_token ()->get_id () == END_OF_FILE
;
403 // Parses a sequence of items within a module or the implicit top-level module
405 template <typename ManagedTokenSource
>
406 std::vector
<std::unique_ptr
<AST::Item
>>
407 Parser
<ManagedTokenSource
>::parse_items ()
409 std::vector
<std::unique_ptr
<AST::Item
>> items
;
411 const_TokenPtr t
= lexer
.peek_token ();
412 while (t
->get_id () != END_OF_FILE
)
414 std::unique_ptr
<AST::Item
> item
= parse_item (false);
417 Error
error (lexer
.peek_token ()->get_locus (),
418 "failed to parse item in crate");
419 add_error (std::move (error
));
421 // TODO: should all items be cleared?
422 items
= std::vector
<std::unique_ptr
<AST::Item
>> ();
426 items
.push_back (std::move (item
));
428 t
= lexer
.peek_token ();
434 // Parses a crate (compilation unit) - entry point
435 template <typename ManagedTokenSource
>
436 std::unique_ptr
<AST::Crate
>
437 Parser
<ManagedTokenSource
>::parse_crate ()
439 // parse inner attributes
440 AST::AttrVec inner_attrs
= parse_inner_attributes ();
443 std::vector
<std::unique_ptr
<AST::Item
>> items
= parse_items ();
446 for (const auto &error
: error_table
)
449 return std::unique_ptr
<AST::Crate
> (
450 new AST::Crate (std::move (items
), std::move (inner_attrs
)));
453 // Parse a contiguous block of inner attributes.
454 template <typename ManagedTokenSource
>
456 Parser
<ManagedTokenSource
>::parse_inner_attributes ()
458 AST::AttrVec inner_attributes
;
460 // only try to parse it if it starts with "#!" not only "#"
461 while ((lexer
.peek_token ()->get_id () == HASH
462 && lexer
.peek_token (1)->get_id () == EXCLAM
)
463 || lexer
.peek_token ()->get_id () == INNER_DOC_COMMENT
)
465 AST::Attribute inner_attr
= parse_inner_attribute ();
467 /* Ensure only valid inner attributes are added to the inner_attributes
469 if (!inner_attr
.is_empty ())
471 inner_attributes
.push_back (std::move (inner_attr
));
475 /* If no more valid inner attributes, break out of loop (only
476 * contiguous inner attributes parsed). */
481 inner_attributes
.shrink_to_fit ();
482 return inner_attributes
;
485 // Parse a inner or outer doc comment into an doc attribute
486 template <typename ManagedTokenSource
>
488 Parser
<ManagedTokenSource
>::parse_doc_comment ()
490 const_TokenPtr token
= lexer
.peek_token ();
491 Location locus
= token
->get_locus ();
492 AST::SimplePathSegment
segment ("doc", locus
);
493 std::vector
<AST::SimplePathSegment
> segments
;
494 segments
.push_back (std::move (segment
));
495 AST::SimplePath
attr_path (std::move (segments
), false, locus
);
496 AST::LiteralExpr
lit_expr (token
->get_str (), AST::Literal::STRING
,
497 PrimitiveCoreType::CORETYPE_STR
, {}, locus
);
498 std::unique_ptr
<AST::AttrInput
> attr_input (
499 new AST::AttrInputLiteral (std::move (lit_expr
)));
501 return AST::Attribute (std::move (attr_path
), std::move (attr_input
), locus
);
504 // Parse a single inner attribute.
505 template <typename ManagedTokenSource
>
507 Parser
<ManagedTokenSource
>::parse_inner_attribute ()
509 if (lexer
.peek_token ()->get_id () == INNER_DOC_COMMENT
)
510 return parse_doc_comment ();
512 if (lexer
.peek_token ()->get_id () != HASH
)
514 Error
error (lexer
.peek_token ()->get_locus (),
515 "BUG: token %<#%> is missing, but %<parse_inner_attribute%> "
517 add_error (std::move (error
));
519 return AST::Attribute::create_empty ();
523 if (lexer
.peek_token ()->get_id () != EXCLAM
)
525 Error
error (lexer
.peek_token ()->get_locus (),
526 "expected %<!%> or %<[%> for inner attribute");
527 add_error (std::move (error
));
529 return AST::Attribute::create_empty ();
533 if (!skip_token (LEFT_SQUARE
))
534 return AST::Attribute::create_empty ();
536 AST::Attribute actual_attribute
= parse_attribute_body ();
538 if (!skip_token (RIGHT_SQUARE
))
539 return AST::Attribute::create_empty ();
541 return actual_attribute
;
544 // Parses the body of an attribute (inner or outer).
545 template <typename ManagedTokenSource
>
547 Parser
<ManagedTokenSource
>::parse_attribute_body ()
549 Location locus
= lexer
.peek_token ()->get_locus ();
551 AST::SimplePath attr_path
= parse_simple_path ();
552 // ensure path is valid to parse attribute input
553 if (attr_path
.is_empty ())
555 Error
error (lexer
.peek_token ()->get_locus (),
556 "empty simple path in attribute");
557 add_error (std::move (error
));
559 // Skip past potential further info in attribute (i.e. attr_input)
560 skip_after_end_attribute ();
561 return AST::Attribute::create_empty ();
564 std::unique_ptr
<AST::AttrInput
> attr_input
= parse_attr_input ();
565 // AttrInput is allowed to be null, so no checks here
567 return AST::Attribute (std::move (attr_path
), std::move (attr_input
), locus
);
570 /* Determines whether token is a valid simple path segment. This does not
571 * include scope resolution operators. */
573 is_simple_path_segment (TokenId id
)
583 // assume that dollar sign leads to $crate
590 // Parses a SimplePath AST node, if it exists. Does nothing otherwise.
591 template <typename ManagedTokenSource
>
593 Parser
<ManagedTokenSource
>::parse_simple_path ()
595 bool has_opening_scope_resolution
= false;
596 Location locus
= Linemap::unknown_location ();
598 // don't parse anything if not a path upfront
599 if (!is_simple_path_segment (lexer
.peek_token ()->get_id ())
600 && !is_simple_path_segment (lexer
.peek_token (1)->get_id ()))
601 return AST::SimplePath::create_empty ();
603 /* Checks for opening scope resolution (i.e. global scope fully-qualified
605 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
)
607 has_opening_scope_resolution
= true;
609 locus
= lexer
.peek_token ()->get_locus ();
614 // Parse single required simple path segment
615 AST::SimplePathSegment segment
= parse_simple_path_segment ();
617 // get location if not gotten already
618 if (locus
== Linemap::unknown_location ())
619 locus
= segment
.get_locus ();
621 std::vector
<AST::SimplePathSegment
> segments
;
623 // Return empty vector if first, actually required segment is an error
624 if (segment
.is_error ())
625 return AST::SimplePath::create_empty ();
627 segments
.push_back (std::move (segment
));
629 // Parse all other simple path segments
630 while (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
)
632 // Skip scope resolution operator
635 AST::SimplePathSegment new_segment
= parse_simple_path_segment ();
637 // Return path as currently constructed if segment in error state.
638 if (new_segment
.is_error ())
641 segments
.push_back (std::move (new_segment
));
644 // DEBUG: check for any empty segments
645 for (const auto &seg
: segments
)
650 "when parsing simple path, somehow empty path segment was "
651 "not filtered out. Path begins with '%s'",
652 segments
.at (0).as_string ().c_str ());
656 return AST::SimplePath (std::move (segments
), has_opening_scope_resolution
,
658 /* TODO: now that is_simple_path_segment exists, could probably start
659 * actually making errors upon parse failure of segments and whatever */
662 /* Parses a single SimplePathSegment (does not handle the scope resolution
664 template <typename ManagedTokenSource
>
665 AST::SimplePathSegment
666 Parser
<ManagedTokenSource
>::parse_simple_path_segment ()
668 const_TokenPtr t
= lexer
.peek_token ();
669 switch (t
->get_id ())
674 return AST::SimplePathSegment (t
->get_str (), t
->get_locus ());
678 return AST::SimplePathSegment ("super", t
->get_locus ());
682 return AST::SimplePathSegment ("self", t
->get_locus ());
686 return AST::SimplePathSegment ("crate", t
->get_locus ());
688 if (lexer
.peek_token (1)->get_id () == CRATE
)
690 lexer
.skip_token (1);
692 return AST::SimplePathSegment ("$crate", t
->get_locus ());
696 // do nothing but inactivates warning from gcc when compiling
697 /* could put the rust_error_at thing here but fallthrough (from failing
698 * $crate condition) isn't completely obvious if it is. */
700 // test prevent error
701 return AST::SimplePathSegment::create_error ();
705 t->get_locus(), "invalid token '%s' in simple path segment",
706 t->get_token_description());*/
707 // this is not necessarily an error, e.g. end of path
708 // return AST::SimplePathSegment::create_error();
711 // Parses a PathIdentSegment - an identifier segment of a non-SimplePath path.
712 template <typename ManagedTokenSource
>
713 AST::PathIdentSegment
714 Parser
<ManagedTokenSource
>::parse_path_ident_segment ()
716 const_TokenPtr t
= lexer
.peek_token ();
717 switch (t
->get_id ())
722 return AST::PathIdentSegment (t
->get_str (), t
->get_locus ());
726 return AST::PathIdentSegment ("super", t
->get_locus ());
730 return AST::PathIdentSegment ("self", t
->get_locus ());
734 return AST::PathIdentSegment ("Self", t
->get_locus ());
738 return AST::PathIdentSegment ("crate", t
->get_locus ());
740 if (lexer
.peek_token (1)->get_id () == CRATE
)
742 lexer
.skip_token (1);
744 return AST::PathIdentSegment ("$crate", t
->get_locus ());
748 /* do nothing but inactivates warning from gcc when compiling
749 * could put the error_at thing here but fallthrough (from failing $crate
750 * condition) isn't completely obvious if it is. */
752 // test prevent error
753 return AST::PathIdentSegment::create_error ();
756 // not necessarily an error
759 // Parses an AttrInput AST node (polymorphic, as AttrInput is abstract)
760 template <typename ManagedTokenSource
>
761 std::unique_ptr
<AST::AttrInput
>
762 Parser
<ManagedTokenSource
>::parse_attr_input ()
764 const_TokenPtr t
= lexer
.peek_token ();
765 switch (t
->get_id ())
770 // must be a delimited token tree, so parse that
771 std::unique_ptr
<AST::AttrInput
> input_tree (
772 new AST::DelimTokenTree (parse_delim_token_tree ()));
774 // TODO: potential checks on DelimTokenTree before returning
782 t
= lexer
.peek_token ();
784 /* Ensure token is a "literal expression" (literally only a literal
785 * token of any type) */
786 if (!t
->is_literal ())
790 "unknown token %qs in attribute body - literal expected",
791 t
->get_token_description ());
792 add_error (std::move (error
));
794 skip_after_end_attribute ();
798 AST::Literal::LitType lit_type
= AST::Literal::STRING
;
799 // Crappy mapping of token type to literal type
800 switch (t
->get_id ())
803 lit_type
= AST::Literal::INT
;
806 lit_type
= AST::Literal::FLOAT
;
809 lit_type
= AST::Literal::CHAR
;
811 case BYTE_CHAR_LITERAL
:
812 lit_type
= AST::Literal::BYTE
;
814 case BYTE_STRING_LITERAL
:
815 lit_type
= AST::Literal::BYTE_STRING
;
819 lit_type
= AST::Literal::STRING
;
820 break; // TODO: raw string? don't eliminate it from lexer?
823 // create actual LiteralExpr
824 AST::LiteralExpr
lit_expr (t
->get_str (), lit_type
, t
->get_type_hint (),
825 {}, t
->get_locus ());
828 std::unique_ptr
<AST::AttrInput
> attr_input_lit (
829 new AST::AttrInputLiteral (std::move (lit_expr
)));
831 // do checks or whatever? none required, really
833 // FIXME: shouldn't a skip token be required here?
835 return attr_input_lit
;
839 // means AttrInput is missing, which is allowed
843 Error (t
->get_locus (),
844 "unknown token %qs in attribute body - attribute input or "
846 t
->get_token_description ()));
848 skip_after_end_attribute ();
852 // TODO: find out how to stop gcc error on "no return value"
855 /* Returns true if the token id matches the delimiter type. Note that this only
856 * operates for END delimiter tokens. */
858 token_id_matches_delims (TokenId token_id
, AST::DelimType delim_type
)
860 return ((token_id
== RIGHT_PAREN
&& delim_type
== AST::PARENS
)
861 || (token_id
== RIGHT_SQUARE
&& delim_type
== AST::SQUARE
)
862 || (token_id
== RIGHT_CURLY
&& delim_type
== AST::CURLY
));
865 /* Returns true if the likely result of parsing the next few tokens is a path.
866 * Not guaranteed, though, especially in the case of syntax errors. */
868 is_likely_path_next (TokenId next_token_id
)
870 switch (next_token_id
)
877 // maybe - maybe do extra check. But then requires another TokenId.
879 case SCOPE_RESOLUTION
:
886 // Parses a delimited token tree
887 template <typename ManagedTokenSource
>
889 Parser
<ManagedTokenSource
>::parse_delim_token_tree ()
891 const_TokenPtr t
= lexer
.peek_token ();
893 Location initial_loc
= t
->get_locus ();
895 // save delim type to ensure it is reused later
896 AST::DelimType delim_type
= AST::PARENS
;
898 // Map tokens to DelimType
899 switch (t
->get_id ())
902 delim_type
= AST::PARENS
;
905 delim_type
= AST::SQUARE
;
908 delim_type
= AST::CURLY
;
911 add_error (Error (t
->get_locus (),
912 "unexpected token %qs - expecting delimiters (for a "
913 "delimited token tree)",
914 t
->get_token_description ()));
916 return AST::DelimTokenTree::create_empty ();
919 // parse actual token tree vector - 0 or more
920 std::vector
<std::unique_ptr
<AST::TokenTree
>> token_trees_in_tree
;
922 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
923 token_trees_in_tree
.push_back (std::move (delim_open
));
925 // repeat loop until finding the matching delimiter
926 t
= lexer
.peek_token ();
927 while (!token_id_matches_delims (t
->get_id (), delim_type
)
928 && t
->get_id () != END_OF_FILE
)
930 std::unique_ptr
<AST::TokenTree
> tok_tree
= parse_token_tree ();
932 if (tok_tree
== nullptr)
934 // TODO: is this error handling appropriate?
937 "failed to parse token tree in delimited token tree - found %qs",
938 t
->get_token_description ());
939 add_error (std::move (error
));
941 return AST::DelimTokenTree::create_empty ();
944 token_trees_in_tree
.push_back (std::move (tok_tree
));
946 // lexer.skip_token();
947 t
= lexer
.peek_token ();
950 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
951 token_trees_in_tree
.push_back (std::move (delim_close
));
953 AST::DelimTokenTree
token_tree (delim_type
, std::move (token_trees_in_tree
),
956 // parse end delimiters
957 t
= lexer
.peek_token ();
959 if (token_id_matches_delims (t
->get_id (), delim_type
))
961 // tokens match opening delimiter, so skip.
965 rust_debug ("finished parsing new delim token tree - peeked token is now "
966 "'%s' while t is '%s'",
967 lexer
.peek_token ()->get_token_description (),
968 t
->get_token_description ());
974 // tokens don't match opening delimiters, so produce error
975 Error
error (t
->get_locus (),
976 "unexpected token %qs - expecting closing delimiter %qs "
977 "(for a delimited token tree)",
978 t
->get_token_description (),
979 (delim_type
== AST::PARENS
981 : (delim_type
== AST::SQUARE
? "]" : "}")));
982 add_error (std::move (error
));
984 /* return empty token tree despite possibly parsing valid token tree -
985 * TODO is this a good idea? */
986 return AST::DelimTokenTree::create_empty ();
990 /* Parses a TokenTree syntactical production. This is either a delimited token
991 * tree or a non-delimiter token. */
992 template <typename ManagedTokenSource
>
993 std::unique_ptr
<AST::TokenTree
>
994 Parser
<ManagedTokenSource
>::parse_token_tree ()
996 const_TokenPtr t
= lexer
.peek_token ();
998 switch (t
->get_id ())
1003 // Parse delimited token tree
1004 // TODO: use move rather than copy constructor
1005 return std::unique_ptr
<AST::DelimTokenTree
> (
1006 new AST::DelimTokenTree (parse_delim_token_tree ()));
1010 // error - should not be called when this a token
1012 Error (t
->get_locus (),
1013 "unexpected closing delimiter %qs - token tree requires "
1014 "either paired delimiters or non-delimiter tokens",
1015 t
->get_token_description ()));
1017 lexer
.skip_token ();
1020 // parse token itself as TokenTree
1021 lexer
.skip_token ();
1022 return std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
1026 // Parses a single item
1027 template <typename ManagedTokenSource
>
1028 std::unique_ptr
<AST::Item
>
1029 Parser
<ManagedTokenSource
>::parse_item (bool called_from_statement
)
1031 // has a "called_from_statement" parameter for better error message handling
1033 // parse outer attributes for item
1034 AST::AttrVec outer_attrs
= parse_outer_attributes ();
1036 // TODO: decide how to deal with VisItem vs MacroItem dichotomy
1037 /* best current solution: catch all keywords that would imply a VisItem in a
1038 * switch and have MacroItem as a last resort */
1040 const_TokenPtr t
= lexer
.peek_token ();
1042 switch (t
->get_id ())
1045 // not necessarily an error, unless we just read outer
1046 // attributes which needs to be attached
1047 if (!outer_attrs
.empty ())
1049 Rust::AST::Attribute attr
= outer_attrs
.back ();
1050 Error
error (attr
.get_locus (),
1051 "expected item after outer attribute or doc comment");
1052 add_error (std::move (error
));
1067 /* TODO: implement union keyword but not really because of
1068 * context-dependence crappy hack way to parse a union written below to
1069 * separate it from the good code. */
1071 case UNSAFE
: // maybe - unsafe traits are a thing
1072 // if any of these (should be all possible VisItem prefixes), parse a
1074 return parse_vis_item (std::move (outer_attrs
));
1080 // almost certainly macro invocation semi
1081 return parse_macro_item (std::move (outer_attrs
));
1083 // crappy hack to do union "keyword"
1085 // TODO: ensure std::string and literal comparison works
1086 if (t
->get_str () == "union"
1087 && lexer
.peek_token (1)->get_id () == IDENTIFIER
)
1089 return parse_vis_item (std::move (outer_attrs
));
1090 // or should this go straight to parsing union?
1092 else if (t
->get_str () == "macro_rules")
1094 // macro_rules! macro item
1095 return parse_macro_item (std::move (outer_attrs
));
1097 else if (lexer
.peek_token (1)->get_id () == SCOPE_RESOLUTION
1098 || lexer
.peek_token (1)->get_id () == EXCLAM
)
1100 /* path (probably) or macro invocation, so probably a macro invocation
1102 return parse_macro_item (std::move (outer_attrs
));
1106 // otherwise unrecognised
1107 // return parse_macro_item(std::move(outer_attrs));
1108 add_error (Error (t
->get_locus (),
1109 "unrecognised token %qs for start of %s",
1110 t
->get_token_description (),
1111 called_from_statement
? "statement" : "item"));
1119 // Parses a contiguous block of outer attributes.
1120 template <typename ManagedTokenSource
>
1122 Parser
<ManagedTokenSource
>::parse_outer_attributes ()
1124 AST::AttrVec outer_attributes
;
1126 while (lexer
.peek_token ()->get_id ()
1127 == HASH
/* Can also be #!, which catches errors. */
1128 || lexer
.peek_token ()->get_id () == OUTER_DOC_COMMENT
1129 || lexer
.peek_token ()->get_id ()
1130 == INNER_DOC_COMMENT
) /* For error handling. */
1132 AST::Attribute outer_attr
= parse_outer_attribute ();
1134 /* Ensure only valid outer attributes are added to the outer_attributes
1136 if (!outer_attr
.is_empty ())
1138 outer_attributes
.push_back (std::move (outer_attr
));
1142 /* If no more valid outer attributes, break out of loop (only
1143 * contiguous outer attributes parsed). */
1148 outer_attributes
.shrink_to_fit ();
1149 return outer_attributes
;
1151 /* TODO: this shares basically all code with parse_inner_attributes except
1152 * function call - find way of making it more modular? function pointer? */
1155 // Parse a single outer attribute.
1156 template <typename ManagedTokenSource
>
1158 Parser
<ManagedTokenSource
>::parse_outer_attribute ()
1160 if (lexer
.peek_token ()->get_id () == OUTER_DOC_COMMENT
)
1161 return parse_doc_comment ();
1163 if (lexer
.peek_token ()->get_id () == INNER_DOC_COMMENT
)
1166 lexer
.peek_token ()->get_locus (),
1167 "inner doc (%<//!%> or %</*!%>) only allowed at start of item "
1168 "and before any outer attribute or doc (%<#[%>, %<///%> or %</**%>)");
1169 add_error (std::move (error
));
1170 lexer
.skip_token ();
1171 return AST::Attribute::create_empty ();
1174 /* OuterAttribute -> '#' '[' Attr ']' */
1176 if (lexer
.peek_token ()->get_id () != HASH
)
1177 return AST::Attribute::create_empty ();
1179 lexer
.skip_token ();
1181 TokenId id
= lexer
.peek_token ()->get_id ();
1182 if (id
!= LEFT_SQUARE
)
1186 // this is inner attribute syntax, so throw error
1187 // inner attributes were either already parsed or not allowed here.
1189 lexer
.peek_token ()->get_locus (),
1190 "token %<!%> found, indicating inner attribute definition. Inner "
1191 "attributes are not possible at this location");
1192 add_error (std::move (error
));
1194 return AST::Attribute::create_empty ();
1197 lexer
.skip_token ();
1199 AST::Attribute actual_attribute
= parse_attribute_body ();
1201 if (lexer
.peek_token ()->get_id () != RIGHT_SQUARE
)
1202 return AST::Attribute::create_empty ();
1204 lexer
.skip_token ();
1206 return actual_attribute
;
1209 // Parses a VisItem (item that can have non-default visibility).
1210 template <typename ManagedTokenSource
>
1211 std::unique_ptr
<AST::VisItem
>
1212 Parser
<ManagedTokenSource
>::parse_vis_item (AST::AttrVec outer_attrs
)
1214 // parse visibility, which may or may not exist
1215 AST::Visibility vis
= parse_visibility ();
1217 // select VisItem to create depending on keyword
1218 const_TokenPtr t
= lexer
.peek_token ();
1220 switch (t
->get_id ())
1223 return parse_module (std::move (vis
), std::move (outer_attrs
));
1225 // lookahead to resolve syntactical production
1226 t
= lexer
.peek_token (1);
1228 switch (t
->get_id ())
1231 return parse_extern_crate (std::move (vis
), std::move (outer_attrs
));
1232 case FN_TOK
: // extern function
1233 return parse_function (std::move (vis
), std::move (outer_attrs
));
1234 case LEFT_CURLY
: // extern block
1235 return parse_extern_block (std::move (vis
), std::move (outer_attrs
));
1236 case STRING_LITERAL
: // for specifying extern ABI
1237 // could be extern block or extern function, so more lookahead
1238 t
= lexer
.peek_token (2);
1240 switch (t
->get_id ())
1243 return parse_function (std::move (vis
), std::move (outer_attrs
));
1245 return parse_extern_block (std::move (vis
),
1246 std::move (outer_attrs
));
1249 Error (t
->get_locus (),
1250 "unexpected token %qs in some sort of extern production",
1251 t
->get_token_description ()));
1253 lexer
.skip_token (2); // TODO: is this right thing to do?
1258 Error (t
->get_locus (),
1259 "unexpected token %qs in some sort of extern production",
1260 t
->get_token_description ()));
1262 lexer
.skip_token (1); // TODO: is this right thing to do?
1266 return parse_use_decl (std::move (vis
), std::move (outer_attrs
));
1268 return parse_function (std::move (vis
), std::move (outer_attrs
));
1270 return parse_type_alias (std::move (vis
), std::move (outer_attrs
));
1272 return parse_struct (std::move (vis
), std::move (outer_attrs
));
1274 return parse_enum (std::move (vis
), std::move (outer_attrs
));
1275 // TODO: implement union keyword but not really because of
1276 // context-dependence case UNION: crappy hack to do union "keyword"
1278 if (t
->get_str () == "union"
1279 && lexer
.peek_token (1)->get_id () == IDENTIFIER
)
1281 return parse_union (std::move (vis
), std::move (outer_attrs
));
1282 // or should item switch go straight to parsing union?
1289 // lookahead to resolve syntactical production
1290 t
= lexer
.peek_token (1);
1292 switch (t
->get_id ())
1296 return parse_const_item (std::move (vis
), std::move (outer_attrs
));
1300 return parse_function (std::move (vis
), std::move (outer_attrs
));
1303 Error (t
->get_locus (),
1304 "unexpected token %qs in some sort of const production",
1305 t
->get_token_description ()));
1307 lexer
.skip_token (1); // TODO: is this right thing to do?
1311 return parse_static_item (std::move (vis
), std::move (outer_attrs
));
1313 return parse_trait (std::move (vis
), std::move (outer_attrs
));
1315 return parse_impl (std::move (vis
), std::move (outer_attrs
));
1316 case UNSAFE
: // unsafe traits, unsafe functions, unsafe impls (trait impls),
1317 // lookahead to resolve syntactical production
1318 t
= lexer
.peek_token (1);
1320 switch (t
->get_id ())
1323 return parse_trait (std::move (vis
), std::move (outer_attrs
));
1326 return parse_function (std::move (vis
), std::move (outer_attrs
));
1328 return parse_impl (std::move (vis
), std::move (outer_attrs
));
1331 Error (t
->get_locus (),
1332 "unexpected token %qs in some sort of unsafe production",
1333 t
->get_token_description ()));
1335 lexer
.skip_token (1); // TODO: is this right thing to do?
1339 // otherwise vis item clearly doesn't exist, which is not an error
1340 // has a catch-all post-switch return to allow other breaks to occur
1346 // Parses a MacroItem (either a MacroInvocationSemi or MacroRulesDefinition).
1347 template <typename ManagedTokenSource
>
1348 std::unique_ptr
<AST::MacroItem
>
1349 Parser
<ManagedTokenSource
>::parse_macro_item (AST::AttrVec outer_attrs
)
1351 const_TokenPtr t
= lexer
.peek_token ();
1353 /* dodgy way of detecting macro due to weird context-dependence thing.
1354 * probably can be improved */
1355 // TODO: ensure that string compare works properly
1356 if (t
->get_id () == IDENTIFIER
&& t
->get_str () == "macro_rules")
1358 return parse_macro_rules_def (std::move (outer_attrs
));
1362 // DEBUG: TODO: remove
1364 "DEBUG - parse_macro_item called and token is not macro_rules");
1365 if (t
->get_id () == IDENTIFIER
)
1367 rust_debug ("just add to last error: token is not macro_rules and is "
1369 t
->get_str ().c_str ());
1373 rust_debug ("just add to last error: token is not macro_rules and is "
1374 "not an identifier either - it is '%s'",
1375 t
->get_token_description ());
1378 return parse_macro_invocation_semi (std::move (outer_attrs
));
1382 // Parses a macro rules definition syntax extension whatever thing.
1383 template <typename ManagedTokenSource
>
1384 std::unique_ptr
<AST::MacroRulesDefinition
>
1385 Parser
<ManagedTokenSource
>::parse_macro_rules_def (AST::AttrVec outer_attrs
)
1387 // ensure that first token is identifier saying "macro_rules"
1388 const_TokenPtr t
= lexer
.peek_token ();
1389 if (t
->get_id () != IDENTIFIER
|| t
->get_str () != "macro_rules")
1393 "macro rules definition does not start with %<macro_rules%>");
1394 add_error (std::move (error
));
1396 // skip after somewhere?
1399 lexer
.skip_token ();
1400 Location macro_locus
= t
->get_locus ();
1402 if (!skip_token (EXCLAM
))
1404 // skip after somewhere?
1409 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
1410 if (ident_tok
== nullptr)
1414 Identifier rule_name
= ident_tok
->get_str ();
1417 rust_debug ("in macro rules def, about to parse parens.");
1419 // save delim type to ensure it is reused later
1420 AST::DelimType delim_type
= AST::PARENS
;
1422 // Map tokens to DelimType
1423 t
= lexer
.peek_token ();
1424 switch (t
->get_id ())
1427 delim_type
= AST::PARENS
;
1430 delim_type
= AST::SQUARE
;
1433 delim_type
= AST::CURLY
;
1436 add_error (Error (t
->get_locus (),
1437 "unexpected token %qs - expecting delimiters (for a "
1438 "macro rules definition)",
1439 t
->get_token_description ()));
1443 lexer
.skip_token ();
1445 // parse actual macro rules
1446 std::vector
<AST::MacroRule
> macro_rules
;
1448 // must be at least one macro rule, so parse it
1449 AST::MacroRule initial_rule
= parse_macro_rule ();
1450 if (initial_rule
.is_error ())
1452 Error
error (lexer
.peek_token ()->get_locus (),
1453 "required first macro rule in macro rules definition "
1454 "could not be parsed");
1455 add_error (std::move (error
));
1457 // skip after somewhere?
1460 macro_rules
.push_back (std::move (initial_rule
));
1463 rust_debug ("successfully pushed back initial macro rule");
1465 t
= lexer
.peek_token ();
1466 // parse macro rules
1467 while (t
->get_id () == SEMICOLON
)
1470 lexer
.skip_token ();
1472 // don't parse if end of macro rules
1473 if (token_id_matches_delims (lexer
.peek_token ()->get_id (), delim_type
))
1477 "broke out of parsing macro rules loop due to finding delim");
1482 // try to parse next rule
1483 AST::MacroRule rule
= parse_macro_rule ();
1484 if (rule
.is_error ())
1486 Error
error (lexer
.peek_token ()->get_locus (),
1487 "failed to parse macro rule in macro rules definition");
1488 add_error (std::move (error
));
1493 macro_rules
.push_back (std::move (rule
));
1496 rust_debug ("successfully pushed back another macro rule");
1498 t
= lexer
.peek_token ();
1501 // parse end delimiters
1502 t
= lexer
.peek_token ();
1503 if (token_id_matches_delims (t
->get_id (), delim_type
))
1505 // tokens match opening delimiter, so skip.
1506 lexer
.skip_token ();
1508 if (delim_type
!= AST::CURLY
)
1510 // skip semicolon at end of non-curly macro definitions
1511 if (!skip_token (SEMICOLON
))
1513 // as this is the end, allow recovery (probably) - may change
1514 return std::unique_ptr
<AST::MacroRulesDefinition
> (
1515 new AST::MacroRulesDefinition (
1516 std::move (rule_name
), delim_type
, std::move (macro_rules
),
1517 std::move (outer_attrs
), macro_locus
));
1521 return std::unique_ptr
<AST::MacroRulesDefinition
> (
1522 new AST::MacroRulesDefinition (std::move (rule_name
), delim_type
,
1523 std::move (macro_rules
),
1524 std::move (outer_attrs
), macro_locus
));
1528 // tokens don't match opening delimiters, so produce error
1529 Error
error (t
->get_locus (),
1530 "unexpected token %qs - expecting closing delimiter %qs "
1531 "(for a macro rules definition)",
1532 t
->get_token_description (),
1533 (delim_type
== AST::PARENS
1535 : (delim_type
== AST::SQUARE
? "]" : "}")));
1536 add_error (std::move (error
));
1538 /* return empty macro definiton despite possibly parsing mostly valid one
1539 * - TODO is this a good idea? */
1544 // Parses a semi-coloned (except for full block) macro invocation item.
1545 template <typename ManagedTokenSource
>
1546 std::unique_ptr
<AST::MacroInvocation
>
1547 Parser
<ManagedTokenSource
>::parse_macro_invocation_semi (
1548 AST::AttrVec outer_attrs
)
1550 Location macro_locus
= lexer
.peek_token ()->get_locus ();
1551 AST::SimplePath path
= parse_simple_path ();
1553 if (!skip_token (EXCLAM
))
1555 // skip after somewhere?
1559 // save delim type to ensure it is reused later
1560 AST::DelimType delim_type
= AST::PARENS
;
1562 // Map tokens to DelimType
1563 const_TokenPtr t
= lexer
.peek_token ();
1564 switch (t
->get_id ())
1567 delim_type
= AST::PARENS
;
1570 delim_type
= AST::SQUARE
;
1573 delim_type
= AST::CURLY
;
1576 add_error (Error (t
->get_locus (),
1577 "unexpected token %qs - expecting delimiters (for a "
1578 "macro invocation semi body)",
1579 t
->get_token_description ()));
1583 Location tok_tree_locus
= t
->get_locus ();
1584 lexer
.skip_token ();
1586 // parse actual token trees
1587 std::vector
<std::unique_ptr
<AST::TokenTree
>> token_trees
;
1589 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
1590 token_trees
.push_back (std::move (delim_open
));
1592 t
= lexer
.peek_token ();
1593 // parse token trees until the initial delimiter token is found again
1594 while (!token_id_matches_delims (t
->get_id (), delim_type
))
1596 std::unique_ptr
<AST::TokenTree
> tree
= parse_token_tree ();
1598 if (tree
== nullptr)
1600 Error
error (t
->get_locus (),
1601 "failed to parse token tree for macro invocation semi "
1603 t
->get_token_description ());
1604 add_error (std::move (error
));
1609 token_trees
.push_back (std::move (tree
));
1611 t
= lexer
.peek_token ();
1614 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
1615 token_trees
.push_back (std::move (delim_close
));
1617 AST::DelimTokenTree
delim_tok_tree (delim_type
, std::move (token_trees
),
1619 AST::MacroInvocData
invoc_data (std::move (path
), std::move (delim_tok_tree
));
1621 // parse end delimiters
1622 t
= lexer
.peek_token ();
1623 if (token_id_matches_delims (t
->get_id (), delim_type
))
1625 // tokens match opening delimiter, so skip.
1626 lexer
.skip_token ();
1628 if (delim_type
!= AST::CURLY
)
1630 // skip semicolon at end of non-curly macro invocation semis
1631 if (!skip_token (SEMICOLON
))
1633 // as this is the end, allow recovery (probably) - may change
1635 return std::unique_ptr
<AST::MacroInvocation
> (
1636 new AST::MacroInvocation (std::move (invoc_data
),
1637 std::move (outer_attrs
), macro_locus
,
1643 rust_debug ("skipped token is '%s', next token (current peek) is '%s'",
1644 t
->get_token_description (),
1645 lexer
.peek_token ()->get_token_description ());
1647 return std::unique_ptr
<AST::MacroInvocation
> (
1648 new AST::MacroInvocation (std::move (invoc_data
),
1649 std::move (outer_attrs
), macro_locus
, true));
1653 // tokens don't match opening delimiters, so produce error
1654 Error
error (t
->get_locus (),
1655 "unexpected token %qs - expecting closing delimiter %qs "
1656 "(for a macro invocation semi)",
1657 t
->get_token_description (),
1658 (delim_type
== AST::PARENS
1660 : (delim_type
== AST::SQUARE
? "]" : "}")));
1661 add_error (std::move (error
));
1663 /* return empty macro invocation despite possibly parsing mostly valid one
1664 * - TODO is this a good idea? */
1669 // Parses a non-semicoloned macro invocation (i.e. as pattern or expression).
1670 template <typename ManagedTokenSource
>
1671 std::unique_ptr
<AST::MacroInvocation
>
1672 Parser
<ManagedTokenSource
>::parse_macro_invocation (AST::AttrVec outer_attrs
)
1675 AST::SimplePath macro_path
= parse_simple_path ();
1676 if (macro_path
.is_empty ())
1678 Error
error (lexer
.peek_token ()->get_locus (),
1679 "failed to parse macro invocation path");
1680 add_error (std::move (error
));
1686 if (!skip_token (EXCLAM
))
1688 // skip after somewhere?
1692 // parse internal delim token tree
1693 AST::DelimTokenTree delim_tok_tree
= parse_delim_token_tree ();
1695 Location macro_locus
= macro_path
.get_locus ();
1697 return std::unique_ptr
<AST::MacroInvocation
> (
1698 new AST::MacroInvocation (AST::MacroInvocData (std::move (macro_path
),
1699 std::move (delim_tok_tree
)),
1700 std::move (outer_attrs
), macro_locus
));
1703 // Parses a macro rule definition - does not parse semicolons.
1704 template <typename ManagedTokenSource
>
1706 Parser
<ManagedTokenSource
>::parse_macro_rule ()
1708 Location locus
= lexer
.peek_token ()->get_locus ();
1710 // parse macro matcher
1711 AST::MacroMatcher matcher
= parse_macro_matcher ();
1713 if (matcher
.is_error ())
1714 return AST::MacroRule::create_error (locus
);
1716 if (!skip_token (MATCH_ARROW
))
1718 // skip after somewhere?
1719 return AST::MacroRule::create_error (locus
);
1722 // parse transcriber (this is just a delim token tree)
1723 Location token_tree_loc
= lexer
.peek_token ()->get_locus ();
1724 AST::MacroTranscriber
transcriber (parse_delim_token_tree (), token_tree_loc
);
1726 return AST::MacroRule (std::move (matcher
), std::move (transcriber
), locus
);
1729 // Parses a macro matcher (part of a macro rule definition).
1730 template <typename ManagedTokenSource
>
1732 Parser
<ManagedTokenSource
>::parse_macro_matcher ()
1734 // save delim type to ensure it is reused later
1735 AST::DelimType delim_type
= AST::PARENS
;
1738 rust_debug ("begun parsing macro matcher");
1740 // Map tokens to DelimType
1741 const_TokenPtr t
= lexer
.peek_token ();
1742 Location locus
= t
->get_locus ();
1743 switch (t
->get_id ())
1746 delim_type
= AST::PARENS
;
1749 delim_type
= AST::SQUARE
;
1752 delim_type
= AST::CURLY
;
1757 "unexpected token %qs - expecting delimiters (for a macro matcher)",
1758 t
->get_token_description ()));
1760 return AST::MacroMatcher::create_error (t
->get_locus ());
1762 lexer
.skip_token ();
1764 // parse actual macro matches
1765 std::vector
<std::unique_ptr
<AST::MacroMatch
>> matches
;
1766 // Set of possible preceding macro matches to make sure follow-set
1767 // restrictions are respected.
1768 // TODO: Consider using std::reference_wrapper instead of raw pointers?
1769 std::vector
<const AST::MacroMatch
*> last_matches
;
1771 t
= lexer
.peek_token ();
1772 // parse token trees until the initial delimiter token is found again
1773 while (!token_id_matches_delims (t
->get_id (), delim_type
))
1775 std::unique_ptr
<AST::MacroMatch
> match
= parse_macro_match ();
1777 if (match
== nullptr)
1781 "failed to parse macro match for macro matcher - found %qs",
1782 t
->get_token_description ());
1783 add_error (std::move (error
));
1785 return AST::MacroMatcher::create_error (t
->get_locus ());
1788 if (matches
.size () > 0)
1790 const auto *last_match
= matches
.back ().get ();
1792 // We want to check if we are dealing with a zeroable repetition
1793 bool zeroable
= false;
1794 if (last_match
->get_macro_match_type ()
1795 == AST::MacroMatch::MacroMatchType::Repetition
)
1798 = static_cast<const AST::MacroMatchRepetition
*> (last_match
);
1800 if (repetition
->get_op ()
1801 != AST::MacroMatchRepetition::MacroRepOp::ONE_OR_MORE
)
1806 last_matches
.clear ();
1808 last_matches
.emplace_back (last_match
);
1810 for (auto last
: last_matches
)
1811 if (!is_match_compatible (*last
, *match
))
1812 return AST::MacroMatcher::create_error (
1813 match
->get_match_locus ());
1816 matches
.push_back (std::move (match
));
1819 rust_debug ("pushed back a match in macro matcher");
1821 t
= lexer
.peek_token ();
1824 // parse end delimiters
1825 t
= lexer
.peek_token ();
1826 if (token_id_matches_delims (t
->get_id (), delim_type
))
1828 // tokens match opening delimiter, so skip.
1829 lexer
.skip_token ();
1831 return AST::MacroMatcher (delim_type
, std::move (matches
), locus
);
1835 // tokens don't match opening delimiters, so produce error
1836 Error
error (t
->get_locus (),
1837 "unexpected token %qs - expecting closing delimiter %qs "
1838 "(for a macro matcher)",
1839 t
->get_token_description (),
1840 (delim_type
== AST::PARENS
1842 : (delim_type
== AST::SQUARE
? "]" : "}")));
1843 add_error (std::move (error
));
1845 /* return error macro matcher despite possibly parsing mostly correct one?
1846 * TODO is this the best idea? */
1847 return AST::MacroMatcher::create_error (t
->get_locus ());
1851 // Parses a macro match (syntax match inside a matcher in a macro rule).
1852 template <typename ManagedTokenSource
>
1853 std::unique_ptr
<AST::MacroMatch
>
1854 Parser
<ManagedTokenSource
>::parse_macro_match ()
1856 // branch based on token available
1857 const_TokenPtr t
= lexer
.peek_token ();
1858 switch (t
->get_id ())
1863 // must be macro matcher as delimited
1864 AST::MacroMatcher matcher
= parse_macro_matcher ();
1865 if (matcher
.is_error ())
1867 Error
error (lexer
.peek_token ()->get_locus (),
1868 "failed to parse macro matcher in macro match");
1869 add_error (std::move (error
));
1873 return std::unique_ptr
<AST::MacroMatcher
> (
1874 new AST::MacroMatcher (std::move (matcher
)));
1877 // have to do more lookahead to determine if fragment or repetition
1878 const_TokenPtr t2
= lexer
.peek_token (1);
1879 switch (t2
->get_id ())
1933 return parse_macro_match_fragment ();
1936 return parse_macro_match_repetition ();
1938 // error: unrecognised
1940 Error (t2
->get_locus (),
1941 "unrecognised token combination %<$%s%> at start of "
1942 "macro match - did you mean %<$identifier%> or %<$(%>?",
1943 t2
->get_token_description ()));
1955 "closing delimiters like %qs are not allowed at the start of a macro "
1957 t
->get_token_description ()));
1963 lexer
.skip_token ();
1964 return std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
1968 // Parses a fragment macro match.
1969 template <typename ManagedTokenSource
>
1970 std::unique_ptr
<AST::MacroMatchFragment
>
1971 Parser
<ManagedTokenSource
>::parse_macro_match_fragment ()
1973 Location fragment_locus
= lexer
.peek_token ()->get_locus ();
1974 skip_token (DOLLAR_SIGN
);
1976 Identifier ident
= "";
1977 auto identifier
= lexer
.peek_token ();
1978 if (identifier
->has_str ())
1979 ident
= identifier
->get_str ();
1981 ident
= std::string (token_id_to_str (identifier
->get_id ()));
1985 Error
error (lexer
.peek_token ()->get_locus (),
1986 "missing identifier in macro match fragment");
1987 add_error (std::move (error
));
1991 skip_token (identifier
->get_id ());
1993 if (!skip_token (COLON
))
1995 // skip after somewhere?
1999 // get MacroFragSpec for macro
2000 const_TokenPtr t
= expect_token (IDENTIFIER
);
2004 AST::MacroFragSpec frag
2005 = AST::MacroFragSpec::get_frag_spec_from_str (t
->get_str ());
2006 if (frag
.is_error ())
2008 Error
error (t
->get_locus (),
2009 "invalid fragment specifier %qs in fragment macro match",
2010 t
->get_str ().c_str ());
2011 add_error (std::move (error
));
2016 return std::unique_ptr
<AST::MacroMatchFragment
> (
2017 new AST::MacroMatchFragment (std::move (ident
), frag
, fragment_locus
));
2020 // Parses a repetition macro match.
2021 template <typename ManagedTokenSource
>
2022 std::unique_ptr
<AST::MacroMatchRepetition
>
2023 Parser
<ManagedTokenSource
>::parse_macro_match_repetition ()
2025 skip_token (DOLLAR_SIGN
);
2026 skip_token (LEFT_PAREN
);
2028 std::vector
<std::unique_ptr
<AST::MacroMatch
>> matches
;
2030 // parse required first macro match
2031 std::unique_ptr
<AST::MacroMatch
> initial_match
= parse_macro_match ();
2032 if (initial_match
== nullptr)
2035 lexer
.peek_token ()->get_locus (),
2036 "could not parse required first macro match in macro match repetition");
2037 add_error (std::move (error
));
2039 // skip after somewhere?
2042 matches
.push_back (std::move (initial_match
));
2044 // parse optional later macro matches
2045 const_TokenPtr t
= lexer
.peek_token ();
2046 while (t
->get_id () != RIGHT_PAREN
)
2048 std::unique_ptr
<AST::MacroMatch
> match
= parse_macro_match ();
2050 if (match
== nullptr)
2052 Error
error (lexer
.peek_token ()->get_locus (),
2053 "failed to parse macro match in macro match repetition");
2054 add_error (std::move (error
));
2059 matches
.push_back (std::move (match
));
2061 t
= lexer
.peek_token ();
2064 if (!skip_token (RIGHT_PAREN
))
2066 // skip after somewhere?
2070 t
= lexer
.peek_token ();
2071 // see if separator token exists
2072 std::unique_ptr
<AST::Token
> separator
= nullptr;
2073 switch (t
->get_id ())
2075 // repetition operators
2086 // separator does not exist, so still null and don't skip token
2089 // separator does exist
2090 separator
= std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t
)));
2091 lexer
.skip_token ();
2095 // parse repetition operator
2096 t
= lexer
.peek_token ();
2097 AST::MacroMatchRepetition::MacroRepOp op
= AST::MacroMatchRepetition::NONE
;
2098 switch (t
->get_id ())
2101 op
= AST::MacroMatchRepetition::ANY
;
2102 lexer
.skip_token ();
2105 op
= AST::MacroMatchRepetition::ONE_OR_MORE
;
2106 lexer
.skip_token ();
2109 op
= AST::MacroMatchRepetition::ZERO_OR_ONE
;
2110 lexer
.skip_token ();
2114 Error (t
->get_locus (),
2115 "expected macro repetition operator (%<*%>, %<+%>, or %<?%>) in "
2116 "macro match - found %qs",
2117 t
->get_token_description ()));
2119 // skip after somewhere?
2123 return std::unique_ptr
<AST::MacroMatchRepetition
> (
2124 new AST::MacroMatchRepetition (std::move (matches
), op
,
2125 std::move (separator
), t
->get_locus ()));
2128 /* Parses a visibility syntactical production (i.e. creating a non-default
2130 template <typename ManagedTokenSource
>
2132 Parser
<ManagedTokenSource
>::parse_visibility ()
2134 // check for no visibility
2135 if (lexer
.peek_token ()->get_id () != PUB
)
2137 return AST::Visibility::create_private ();
2140 lexer
.skip_token ();
2142 // create simple pub visibility if no parentheses
2143 if (lexer
.peek_token ()->get_id () != LEFT_PAREN
)
2145 return AST::Visibility::create_public ();
2149 lexer
.skip_token ();
2151 const_TokenPtr t
= lexer
.peek_token ();
2152 auto path_loc
= t
->get_locus ();
2154 switch (t
->get_id ())
2157 lexer
.skip_token ();
2159 skip_token (RIGHT_PAREN
);
2161 return AST::Visibility::create_crate (path_loc
);
2163 lexer
.skip_token ();
2165 skip_token (RIGHT_PAREN
);
2167 return AST::Visibility::create_self (path_loc
);
2169 lexer
.skip_token ();
2171 skip_token (RIGHT_PAREN
);
2173 return AST::Visibility::create_super (path_loc
);
2175 lexer
.skip_token ();
2177 // parse the "in" path as well
2178 AST::SimplePath path
= parse_simple_path ();
2179 if (path
.is_empty ())
2181 Error
error (lexer
.peek_token ()->get_locus (),
2182 "missing path in pub(in path) visibility");
2183 add_error (std::move (error
));
2185 // skip after somewhere?
2186 return AST::Visibility::create_error ();
2189 skip_token (RIGHT_PAREN
);
2191 return AST::Visibility::create_in_path (std::move (path
));
2194 add_error (Error (t
->get_locus (), "unexpected token %qs in visibility",
2195 t
->get_token_description ()));
2197 lexer
.skip_token ();
2198 return AST::Visibility::create_error ();
2202 // Parses a module - either a bodied module or a module defined in another file.
2203 template <typename ManagedTokenSource
>
2204 std::unique_ptr
<AST::Module
>
2205 Parser
<ManagedTokenSource
>::parse_module (AST::Visibility vis
,
2206 AST::AttrVec outer_attrs
)
2208 Location locus
= lexer
.peek_token ()->get_locus ();
2211 const_TokenPtr module_name
= expect_token (IDENTIFIER
);
2212 if (module_name
== nullptr)
2216 Identifier name
= module_name
->get_str ();
2218 const_TokenPtr t
= lexer
.peek_token ();
2220 switch (t
->get_id ())
2223 lexer
.skip_token ();
2225 // Construct an external module
2226 return std::unique_ptr
<AST::Module
> (
2227 new AST::Module (std::move (name
), std::move (vis
),
2228 std::move (outer_attrs
), locus
, lexer
.get_filename (),
2229 inline_module_stack
));
2231 lexer
.skip_token ();
2233 // parse inner attributes
2234 AST::AttrVec inner_attrs
= parse_inner_attributes ();
2236 std::string module_path_name
2237 = extract_module_path (inner_attrs
, outer_attrs
, name
);
2238 InlineModuleStackScope
scope (*this, std::move (module_path_name
));
2241 std::vector
<std::unique_ptr
<AST::Item
>> items
;
2242 const_TokenPtr tok
= lexer
.peek_token ();
2243 while (tok
->get_id () != RIGHT_CURLY
)
2245 std::unique_ptr
<AST::Item
> item
= parse_item (false);
2246 if (item
== nullptr)
2248 Error
error (tok
->get_locus (),
2249 "failed to parse item in module");
2250 add_error (std::move (error
));
2255 items
.push_back (std::move (item
));
2257 tok
= lexer
.peek_token ();
2260 if (!skip_token (RIGHT_CURLY
))
2266 return std::unique_ptr
<AST::Module
> (
2267 new AST::Module (std::move (name
), locus
, std::move (items
),
2268 std::move (vis
), std::move (inner_attrs
),
2269 std::move (outer_attrs
))); // module name?
2273 Error (t
->get_locus (),
2274 "unexpected token %qs in module declaration/definition item",
2275 t
->get_token_description ()));
2277 lexer
.skip_token ();
2282 // Parses an extern crate declaration (dependency on external crate)
2283 template <typename ManagedTokenSource
>
2284 std::unique_ptr
<AST::ExternCrate
>
2285 Parser
<ManagedTokenSource
>::parse_extern_crate (AST::Visibility vis
,
2286 AST::AttrVec outer_attrs
)
2288 Location locus
= lexer
.peek_token ()->get_locus ();
2289 if (!skip_token (EXTERN_TOK
))
2291 skip_after_semicolon ();
2295 if (!skip_token (CRATE
))
2297 skip_after_semicolon ();
2301 /* parse crate reference name - this has its own syntactical rule in reference
2302 * but seems to not be used elsewhere, so i'm putting it here */
2303 const_TokenPtr crate_name_tok
= lexer
.peek_token ();
2304 std::string crate_name
;
2306 switch (crate_name_tok
->get_id ())
2309 crate_name
= crate_name_tok
->get_str ();
2310 lexer
.skip_token ();
2313 crate_name
= "self";
2314 lexer
.skip_token ();
2318 Error (crate_name_tok
->get_locus (),
2319 "expecting crate name (identifier or %<self%>), found %qs",
2320 crate_name_tok
->get_token_description ()));
2322 skip_after_semicolon ();
2326 // don't parse as clause if it doesn't exist
2327 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
2329 lexer
.skip_token ();
2331 return std::unique_ptr
<AST::ExternCrate
> (
2332 new AST::ExternCrate (std::move (crate_name
), std::move (vis
),
2333 std::move (outer_attrs
), locus
));
2336 /* parse as clause - this also has its own syntactical rule in reference and
2337 * also seems to not be used elsewhere, so including here again. */
2338 if (!skip_token (AS
))
2340 skip_after_semicolon ();
2344 const_TokenPtr as_name_tok
= lexer
.peek_token ();
2345 std::string as_name
;
2347 switch (as_name_tok
->get_id ())
2350 as_name
= as_name_tok
->get_str ();
2351 lexer
.skip_token ();
2355 lexer
.skip_token ();
2359 Error (as_name_tok
->get_locus (),
2360 "expecting as clause name (identifier or %<_%>), found %qs",
2361 as_name_tok
->get_token_description ()));
2363 skip_after_semicolon ();
2367 if (!skip_token (SEMICOLON
))
2369 skip_after_semicolon ();
2373 return std::unique_ptr
<AST::ExternCrate
> (
2374 new AST::ExternCrate (std::move (crate_name
), std::move (vis
),
2375 std::move (outer_attrs
), locus
, std::move (as_name
)));
2378 // Parses a use declaration.
2379 template <typename ManagedTokenSource
>
2380 std::unique_ptr
<AST::UseDeclaration
>
2381 Parser
<ManagedTokenSource
>::parse_use_decl (AST::Visibility vis
,
2382 AST::AttrVec outer_attrs
)
2384 Location locus
= lexer
.peek_token ()->get_locus ();
2385 if (!skip_token (USE
))
2387 skip_after_semicolon ();
2391 // parse use tree, which is required
2392 std::unique_ptr
<AST::UseTree
> use_tree
= parse_use_tree ();
2393 if (use_tree
== nullptr)
2395 Error
error (lexer
.peek_token ()->get_locus (),
2396 "could not parse use tree in use declaration");
2397 add_error (std::move (error
));
2399 skip_after_semicolon ();
2403 if (!skip_token (SEMICOLON
))
2405 skip_after_semicolon ();
2409 return std::unique_ptr
<AST::UseDeclaration
> (
2410 new AST::UseDeclaration (std::move (use_tree
), std::move (vis
),
2411 std::move (outer_attrs
), locus
));
2414 // Parses a use tree (which can be recursive and is actually a base class).
2415 template <typename ManagedTokenSource
>
2416 std::unique_ptr
<AST::UseTree
>
2417 Parser
<ManagedTokenSource
>::parse_use_tree ()
2419 /* potential syntax definitions in attempt to get algorithm:
2421 * <- SimplePath :: *
2424 * Nested tree thing:
2425 * <- SimplePath :: { COMPLICATED_INNER_TREE_THING }
2426 * <- :: COMPLICATED_INNER_TREE_THING }
2427 * <- { COMPLICATED_INNER_TREE_THING }
2429 * <- SimplePath as IDENTIFIER
2430 * <- SimplePath as _
2434 /* current plan of attack: try to parse SimplePath first - if fails, one of
2435 * top two then try parse :: - if fails, one of top two. Next is deciding
2436 * character for top two. */
2438 /* Thus, parsing smaller parts of use tree may require feeding into function
2439 * via parameters (or could handle all in this single function because other
2440 * use tree types aren't recognised as separate in the spec) */
2442 // TODO: I think this function is too complex, probably should split it
2444 Location locus
= lexer
.peek_token ()->get_locus ();
2446 // bool has_path = false;
2447 AST::SimplePath path
= parse_simple_path ();
2449 if (path
.is_empty ())
2451 // has no path, so must be glob or nested tree UseTree type
2453 bool is_global
= false;
2455 // check for global scope resolution operator
2456 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
)
2458 lexer
.skip_token ();
2462 const_TokenPtr t
= lexer
.peek_token ();
2463 switch (t
->get_id ())
2466 // glob UseTree type
2467 lexer
.skip_token ();
2470 return std::unique_ptr
<AST::UseTreeGlob
> (
2471 new AST::UseTreeGlob (AST::UseTreeGlob::GLOBAL
,
2472 AST::SimplePath::create_empty (), locus
));
2474 return std::unique_ptr
<AST::UseTreeGlob
> (
2475 new AST::UseTreeGlob (AST::UseTreeGlob::NO_PATH
,
2476 AST::SimplePath::create_empty (), locus
));
2478 // nested tree UseTree type
2479 lexer
.skip_token ();
2481 std::vector
<std::unique_ptr
<AST::UseTree
>> use_trees
;
2483 const_TokenPtr t
= lexer
.peek_token ();
2484 while (t
->get_id () != RIGHT_CURLY
)
2486 std::unique_ptr
<AST::UseTree
> use_tree
= parse_use_tree ();
2487 if (use_tree
== nullptr)
2492 use_trees
.push_back (std::move (use_tree
));
2494 if (lexer
.peek_token ()->get_id () != COMMA
)
2497 lexer
.skip_token ();
2498 t
= lexer
.peek_token ();
2501 // skip end curly delimiter
2502 if (!skip_token (RIGHT_CURLY
))
2504 // skip after somewhere?
2509 return std::unique_ptr
<AST::UseTreeList
> (
2510 new AST::UseTreeList (AST::UseTreeList::GLOBAL
,
2511 AST::SimplePath::create_empty (),
2512 std::move (use_trees
), locus
));
2514 return std::unique_ptr
<AST::UseTreeList
> (
2515 new AST::UseTreeList (AST::UseTreeList::NO_PATH
,
2516 AST::SimplePath::create_empty (),
2517 std::move (use_trees
), locus
));
2520 // this is not allowed
2523 "use declaration with rebind %<as%> requires a valid simple path - "
2526 skip_after_semicolon ();
2529 add_error (Error (t
->get_locus (),
2530 "unexpected token %qs in use tree with "
2531 "no valid simple path (i.e. list"
2532 " or glob use tree)",
2533 t
->get_token_description ()));
2535 skip_after_semicolon ();
2541 /* Due to aforementioned implementation issues, the trailing :: token is
2542 * consumed by the path, so it can not be used as a disambiguator.
2543 * NOPE, not true anymore - TODO what are the consequences of this? */
2545 const_TokenPtr t
= lexer
.peek_token ();
2546 switch (t
->get_id ())
2549 // glob UseTree type
2550 lexer
.skip_token ();
2552 return std::unique_ptr
<AST::UseTreeGlob
> (
2553 new AST::UseTreeGlob (AST::UseTreeGlob::PATH_PREFIXED
,
2554 std::move (path
), locus
));
2556 // nested tree UseTree type
2557 lexer
.skip_token ();
2559 std::vector
<std::unique_ptr
<AST::UseTree
>> use_trees
;
2561 // TODO: think of better control structure
2562 const_TokenPtr t
= lexer
.peek_token ();
2563 while (t
->get_id () != RIGHT_CURLY
)
2565 std::unique_ptr
<AST::UseTree
> use_tree
= parse_use_tree ();
2566 if (use_tree
== nullptr)
2571 use_trees
.push_back (std::move (use_tree
));
2573 if (lexer
.peek_token ()->get_id () != COMMA
)
2576 lexer
.skip_token ();
2577 t
= lexer
.peek_token ();
2580 // skip end curly delimiter
2581 if (!skip_token (RIGHT_CURLY
))
2583 // skip after somewhere?
2587 return std::unique_ptr
<AST::UseTreeList
> (
2588 new AST::UseTreeList (AST::UseTreeList::PATH_PREFIXED
,
2589 std::move (path
), std::move (use_trees
),
2593 // rebind UseTree type
2594 lexer
.skip_token ();
2596 const_TokenPtr t
= lexer
.peek_token ();
2597 switch (t
->get_id ())
2601 lexer
.skip_token ();
2603 return std::unique_ptr
<AST::UseTreeRebind
> (
2604 new AST::UseTreeRebind (AST::UseTreeRebind::IDENTIFIER
,
2605 std::move (path
), locus
,
2609 lexer
.skip_token ();
2611 return std::unique_ptr
<AST::UseTreeRebind
> (
2612 new AST::UseTreeRebind (AST::UseTreeRebind::WILDCARD
,
2613 std::move (path
), locus
, "_"));
2617 "unexpected token %qs in use tree with as clause - expected "
2618 "identifier or %<_%>",
2619 t
->get_token_description ()));
2621 skip_after_semicolon ();
2626 // rebind UseTree type without rebinding - path only
2628 // don't skip semicolon - handled in parse_use_tree
2629 // lexer.skip_token();
2631 return std::unique_ptr
<AST::UseTreeRebind
> (
2632 new AST::UseTreeRebind (AST::UseTreeRebind::NONE
, std::move (path
),
2636 // this may occur in recursive calls - assume it is ok and ignore it
2637 return std::unique_ptr
<AST::UseTreeRebind
> (
2638 new AST::UseTreeRebind (AST::UseTreeRebind::NONE
, std::move (path
),
2641 add_error (Error (t
->get_locus (),
2642 "unexpected token %qs in use tree with valid path",
2643 t
->get_token_description ()));
2645 // skip_after_semicolon();
2651 // Parses a function (not a method).
2652 template <typename ManagedTokenSource
>
2653 std::unique_ptr
<AST::Function
>
2654 Parser
<ManagedTokenSource
>::parse_function (AST::Visibility vis
,
2655 AST::AttrVec outer_attrs
)
2657 Location locus
= lexer
.peek_token ()->get_locus ();
2658 // Get qualifiers for function if they exist
2659 AST::FunctionQualifiers qualifiers
= parse_function_qualifiers ();
2661 skip_token (FN_TOK
);
2663 // Save function name token
2664 const_TokenPtr function_name_tok
= expect_token (IDENTIFIER
);
2665 if (function_name_tok
== nullptr)
2667 skip_after_next_block ();
2670 Identifier function_name
= function_name_tok
->get_str ();
2672 // parse generic params - if exist
2673 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
2674 = parse_generic_params_in_angles ();
2676 if (!skip_token (LEFT_PAREN
))
2678 Error
error (lexer
.peek_token ()->get_locus (),
2679 "function declaration missing opening parentheses before "
2681 add_error (std::move (error
));
2683 skip_after_next_block ();
2687 // parse function parameters (only if next token isn't right paren)
2688 std::vector
<AST::FunctionParam
> function_params
;
2689 if (lexer
.peek_token ()->get_id () != RIGHT_PAREN
)
2691 = parse_function_params ([] (TokenId id
) { return id
== RIGHT_PAREN
; });
2693 if (!skip_token (RIGHT_PAREN
))
2695 Error
error (lexer
.peek_token ()->get_locus (),
2696 "function declaration missing closing parentheses after "
2698 add_error (std::move (error
));
2700 skip_after_next_block ();
2704 // parse function return type - if exists
2705 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
2707 // parse where clause - if exists
2708 AST::WhereClause where_clause
= parse_where_clause ();
2710 // parse block expression
2711 std::unique_ptr
<AST::BlockExpr
> block_expr
= parse_block_expr ();
2713 return std::unique_ptr
<AST::Function
> (
2714 new AST::Function (std::move (function_name
), std::move (qualifiers
),
2715 std::move (generic_params
), std::move (function_params
),
2716 std::move (return_type
), std::move (where_clause
),
2717 std::move (block_expr
), std::move (vis
),
2718 std::move (outer_attrs
), locus
));
2721 // Parses function or method qualifiers (i.e. const, unsafe, and extern).
2722 template <typename ManagedTokenSource
>
2723 AST::FunctionQualifiers
2724 Parser
<ManagedTokenSource
>::parse_function_qualifiers ()
2726 AsyncConstStatus const_status
= NONE
;
2727 bool has_unsafe
= false;
2728 bool has_extern
= false;
2731 // Check in order of const, unsafe, then extern
2732 const_TokenPtr t
= lexer
.peek_token ();
2733 Location locus
= t
->get_locus ();
2734 switch (t
->get_id ())
2737 lexer
.skip_token ();
2738 const_status
= CONST_FN
;
2741 lexer
.skip_token ();
2742 const_status
= ASYNC_FN
;
2745 // const status is still none
2749 if (lexer
.peek_token ()->get_id () == UNSAFE
)
2751 lexer
.skip_token ();
2755 if (lexer
.peek_token ()->get_id () == EXTERN_TOK
)
2757 lexer
.skip_token ();
2760 // detect optional abi name
2761 const_TokenPtr next_tok
= lexer
.peek_token ();
2762 if (next_tok
->get_id () == STRING_LITERAL
)
2764 lexer
.skip_token ();
2765 abi
= next_tok
->get_str ();
2769 return AST::FunctionQualifiers (locus
, const_status
, has_unsafe
, has_extern
,
2773 // Parses generic (lifetime or type) params inside angle brackets (optional).
2774 template <typename ManagedTokenSource
>
2775 std::vector
<std::unique_ptr
<AST::GenericParam
>>
2776 Parser
<ManagedTokenSource
>::parse_generic_params_in_angles ()
2778 if (lexer
.peek_token ()->get_id () != LEFT_ANGLE
)
2780 // seems to be no generic params, so exit with empty vector
2781 return std::vector
<std::unique_ptr
<AST::GenericParam
>> ();
2783 lexer
.skip_token ();
2786 rust_debug ("skipped left angle in generic param");
2788 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
2789 = parse_generic_params (is_right_angle_tok
);
2792 rust_debug ("finished parsing actual generic params (i.e. inside angles)");
2794 if (!skip_generics_right_angle ())
2797 rust_debug ("failed to skip generics right angle - returning empty "
2800 return std::vector
<std::unique_ptr
<AST::GenericParam
>> ();
2803 return generic_params
;
2806 template <typename ManagedTokenSource
>
2807 template <typename EndTokenPred
>
2808 std::unique_ptr
<AST::GenericParam
>
2809 Parser
<ManagedTokenSource
>::parse_generic_param (EndTokenPred is_end_token
)
2811 auto token
= lexer
.peek_token ();
2812 auto outer_attrs
= parse_outer_attribute ();
2813 std::unique_ptr
<AST::GenericParam
> param
;
2815 switch (token
->get_id ())
2818 auto lifetime
= parse_lifetime ();
2819 if (lifetime
.is_error ())
2822 token
->get_locus (),
2823 "failed to parse lifetime in generic parameter list");
2827 std::vector
<AST::Lifetime
> lifetime_bounds
;
2828 if (lexer
.peek_token ()->get_id () == COLON
)
2830 lexer
.skip_token ();
2831 // parse required bounds
2833 = parse_lifetime_bounds ([is_end_token
] (TokenId id
) {
2834 return is_end_token (id
) || id
== COMMA
;
2838 param
= std::unique_ptr
<AST::LifetimeParam
> (new AST::LifetimeParam (
2839 std::move (lifetime
), std::move (lifetime_bounds
),
2840 std::move (outer_attrs
), token
->get_locus ()));
2844 auto type_ident
= token
->get_str ();
2845 lexer
.skip_token ();
2847 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
;
2848 if (lexer
.peek_token ()->get_id () == COLON
)
2850 lexer
.skip_token ();
2852 // parse optional type param bounds
2853 type_param_bounds
= parse_type_param_bounds ();
2856 std::unique_ptr
<AST::Type
> type
= nullptr;
2857 if (lexer
.peek_token ()->get_id () == EQUAL
)
2859 lexer
.skip_token ();
2861 // parse required type
2862 type
= parse_type ();
2866 lexer
.peek_token ()->get_locus (),
2867 "failed to parse type in type param in generic params");
2872 param
= std::unique_ptr
<AST::TypeParam
> (
2873 new AST::TypeParam (std::move (type_ident
), token
->get_locus (),
2874 std::move (type_param_bounds
), std::move (type
),
2875 std::move (outer_attrs
)));
2879 lexer
.skip_token ();
2881 auto name_token
= expect_token (IDENTIFIER
);
2883 if (!name_token
|| !expect_token (COLON
))
2886 auto type
= parse_type ();
2890 // optional default value
2891 auto default_expr
= AST::GenericArg::create_error ();
2892 if (lexer
.peek_token ()->get_id () == EQUAL
)
2894 lexer
.skip_token ();
2895 auto tok
= lexer
.peek_token ();
2896 default_expr
= parse_generic_arg ();
2898 if (default_expr
.is_error ())
2899 rust_error_at (tok
->get_locus (),
2900 "invalid token for start of default value for "
2901 "const generic parameter: expected %<block%>, "
2902 "%<identifier%> or %<literal%>, got %qs",
2903 token_id_to_str (tok
->get_id ()));
2905 // At this point, we *know* that we are parsing a const
2907 if (default_expr
.get_kind () == AST::GenericArg::Kind::Either
)
2908 default_expr
= default_expr
.disambiguate_to_const ();
2911 param
= std::unique_ptr
<AST::ConstGenericParam
> (
2912 new AST::ConstGenericParam (name_token
->get_str (), std::move (type
),
2913 default_expr
, std::move (outer_attrs
),
2914 token
->get_locus ()));
2919 // FIXME: Can we clean this last call with a method call?
2920 rust_error_at (token
->get_locus (),
2921 "unexpected token when parsing generic parameters: %qs",
2922 token
->get_str ().c_str ());
2929 /* Parse generic (lifetime or type) params NOT INSIDE ANGLE BRACKETS!!! Almost
2930 * always parse_generic_params_in_angles is what is wanted. */
2931 template <typename ManagedTokenSource
>
2932 template <typename EndTokenPred
>
2933 std::vector
<std::unique_ptr
<AST::GenericParam
>>
2934 Parser
<ManagedTokenSource
>::parse_generic_params (EndTokenPred is_end_token
)
2936 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
;
2938 /* can't parse lifetime and type params separately due to lookahead issues
2939 * thus, parse them all here */
2941 /* HACK: used to retain attribute data if a lifetime param is tentatively
2942 * parsed but it turns out to be type param */
2943 AST::Attribute parsed_outer_attr
= AST::Attribute::create_empty ();
2945 // Did we parse a generic type param yet
2946 auto type_seen
= false;
2947 // Did the user write a lifetime parameter after a type one
2948 auto order_error
= false;
2950 // parse lifetime params
2951 while (!is_end_token (lexer
.peek_token ()->get_id ()))
2953 auto param
= parse_generic_param (is_end_token
);
2956 // TODO: Handle `Const` here as well if necessary
2957 if (param
->get_kind () == AST::GenericParam::Kind::Type
)
2959 else if (param
->get_kind () == AST::GenericParam::Kind::Lifetime
2963 generic_params
.emplace_back (std::move (param
));
2964 maybe_skip_token (COMMA
);
2968 // FIXME: Add reordering hint
2970 rust_error_at (generic_params
.front ()->get_locus (),
2971 "invalid order for generic parameters: lifetimes should "
2972 "always come before types");
2974 generic_params
.shrink_to_fit ();
2975 return generic_params
;
2978 /* Parses lifetime generic parameters (pointers). Will also consume any
2979 * trailing comma. No extra checks for end token. */
2980 template <typename ManagedTokenSource
>
2981 std::vector
<std::unique_ptr
<AST::LifetimeParam
>>
2982 Parser
<ManagedTokenSource
>::parse_lifetime_params ()
2984 std::vector
<std::unique_ptr
<AST::LifetimeParam
>> lifetime_params
;
2986 while (lexer
.peek_token ()->get_id () != END_OF_FILE
)
2988 AST::LifetimeParam lifetime_param
= parse_lifetime_param ();
2990 if (lifetime_param
.is_error ())
2992 // can't treat as error as only way to get out with trailing comma
2996 lifetime_params
.push_back (std::unique_ptr
<AST::LifetimeParam
> (
2997 new AST::LifetimeParam (std::move (lifetime_param
))));
2999 if (lexer
.peek_token ()->get_id () != COMMA
)
3002 // skip commas, including trailing commas
3003 lexer
.skip_token ();
3006 lifetime_params
.shrink_to_fit ();
3008 return lifetime_params
;
3011 /* Parses lifetime generic parameters (pointers). Will also consume any
3012 * trailing comma. Has extra is_end_token predicate checking. */
3013 template <typename ManagedTokenSource
>
3014 template <typename EndTokenPred
>
3015 std::vector
<std::unique_ptr
<AST::LifetimeParam
>>
3016 Parser
<ManagedTokenSource
>::parse_lifetime_params (EndTokenPred is_end_token
)
3018 std::vector
<std::unique_ptr
<AST::LifetimeParam
>> lifetime_params
;
3020 // if end_token is not specified, it defaults to EOF, so should work fine
3021 while (!is_end_token (lexer
.peek_token ()->get_id ()))
3023 AST::LifetimeParam lifetime_param
= parse_lifetime_param ();
3025 if (lifetime_param
.is_error ())
3027 /* TODO: is it worth throwing away all lifetime params just because
3029 Error
error (lexer
.peek_token ()->get_locus (),
3030 "failed to parse lifetime param in lifetime params");
3031 add_error (std::move (error
));
3036 lifetime_params
.push_back (std::unique_ptr
<AST::LifetimeParam
> (
3037 new AST::LifetimeParam (std::move (lifetime_param
))));
3039 if (lexer
.peek_token ()->get_id () != COMMA
)
3042 // skip commas, including trailing commas
3043 lexer
.skip_token ();
3046 lifetime_params
.shrink_to_fit ();
3048 return lifetime_params
;
3051 /* Parses lifetime generic parameters (objects). Will also consume any
3052 * trailing comma. No extra checks for end token.
3053 * TODO: is this best solution? implements most of the same algorithm. */
3054 template <typename ManagedTokenSource
>
3055 std::vector
<AST::LifetimeParam
>
3056 Parser
<ManagedTokenSource
>::parse_lifetime_params_objs ()
3058 std::vector
<AST::LifetimeParam
> lifetime_params
;
3060 // bad control structure as end token cannot be guaranteed
3063 AST::LifetimeParam lifetime_param
= parse_lifetime_param ();
3065 if (lifetime_param
.is_error ())
3067 // not an error as only way to exit if trailing comma
3071 lifetime_params
.push_back (std::move (lifetime_param
));
3073 if (lexer
.peek_token ()->get_id () != COMMA
)
3076 // skip commas, including trailing commas
3077 lexer
.skip_token ();
3080 lifetime_params
.shrink_to_fit ();
3082 return lifetime_params
;
3085 /* Parses lifetime generic parameters (objects). Will also consume any
3086 * trailing comma. Has extra is_end_token predicate checking.
3087 * TODO: is this best solution? implements most of the same algorithm. */
3088 template <typename ManagedTokenSource
>
3089 template <typename EndTokenPred
>
3090 std::vector
<AST::LifetimeParam
>
3091 Parser
<ManagedTokenSource
>::parse_lifetime_params_objs (
3092 EndTokenPred is_end_token
)
3094 std::vector
<AST::LifetimeParam
> lifetime_params
;
3096 while (!is_end_token (lexer
.peek_token ()->get_id ()))
3098 AST::LifetimeParam lifetime_param
= parse_lifetime_param ();
3100 if (lifetime_param
.is_error ())
3102 /* TODO: is it worth throwing away all lifetime params just because
3104 Error
error (lexer
.peek_token ()->get_locus (),
3105 "failed to parse lifetime param in lifetime params");
3106 add_error (std::move (error
));
3111 lifetime_params
.push_back (std::move (lifetime_param
));
3113 if (lexer
.peek_token ()->get_id () != COMMA
)
3116 // skip commas, including trailing commas
3117 lexer
.skip_token ();
3120 lifetime_params
.shrink_to_fit ();
3122 return lifetime_params
;
3125 /* Parses a sequence of a certain grammar rule in object form (not pointer or
3126 * smart pointer), delimited by commas and ending when 'is_end_token' is
3127 * satisfied (templated). Will also consume any trailing comma.
3128 * FIXME: this cannot be used due to member function pointer problems (i.e.
3129 * parsing_function cannot be specified properly) */
3130 template <typename ManagedTokenSource
>
3131 template <typename ParseFunction
, typename EndTokenPred
>
3133 Parser
<ManagedTokenSource
>::parse_non_ptr_sequence (
3134 ParseFunction parsing_function
, EndTokenPred is_end_token
,
3135 std::string error_msg
) -> std::vector
<decltype (parsing_function ())>
3137 std::vector
<decltype (parsing_function ())> params
;
3139 while (!is_end_token (lexer
.peek_token ()->get_id ()))
3141 auto param
= parsing_function ();
3143 if (param
.is_error ())
3145 // TODO: is it worth throwing away all params just because one
3147 Error
error (lexer
.peek_token ()->get_locus (),
3148 std::move (error_msg
));
3149 add_error (std::move (error
));
3154 params
.push_back (std::move (param
));
3156 if (lexer
.peek_token ()->get_id () != COMMA
)
3159 // skip commas, including trailing commas
3160 lexer
.skip_token ();
3163 params
.shrink_to_fit ();
3168 /* Parses a single lifetime generic parameter (not including comma). */
3169 template <typename ManagedTokenSource
>
3171 Parser
<ManagedTokenSource
>::parse_lifetime_param ()
3173 // parse outer attribute, which is optional and may not exist
3174 AST::Attribute outer_attr
= parse_outer_attribute ();
3176 // save lifetime token - required
3177 const_TokenPtr lifetime_tok
= lexer
.peek_token ();
3178 if (lifetime_tok
->get_id () != LIFETIME
)
3180 // if lifetime is missing, must not be a lifetime param, so return null
3181 return AST::LifetimeParam::create_error ();
3183 lexer
.skip_token ();
3184 /* TODO: does this always create a named lifetime? or can a different type
3186 AST::Lifetime
lifetime (AST::Lifetime::NAMED
, lifetime_tok
->get_str (),
3187 lifetime_tok
->get_locus ());
3189 // parse lifetime bounds, if it exists
3190 std::vector
<AST::Lifetime
> lifetime_bounds
;
3191 if (lexer
.peek_token ()->get_id () == COLON
)
3193 // parse lifetime bounds
3194 lifetime_bounds
= parse_lifetime_bounds ();
3195 // TODO: have end token passed in?
3198 return AST::LifetimeParam (std::move (lifetime
), std::move (lifetime_bounds
),
3199 std::move (outer_attr
),
3200 lifetime_tok
->get_locus ());
3203 // Parses type generic parameters. Will also consume any trailing comma.
3204 template <typename ManagedTokenSource
>
3205 std::vector
<std::unique_ptr
<AST::TypeParam
>>
3206 Parser
<ManagedTokenSource
>::parse_type_params ()
3208 std::vector
<std::unique_ptr
<AST::TypeParam
>> type_params
;
3210 // infinite loop with break on failure as no info on ending token
3213 std::unique_ptr
<AST::TypeParam
> type_param
= parse_type_param ();
3215 if (type_param
== nullptr)
3217 // break if fails to parse
3221 type_params
.push_back (std::move (type_param
));
3223 if (lexer
.peek_token ()->get_id () != COMMA
)
3226 // skip commas, including trailing commas
3227 lexer
.skip_token ();
3230 type_params
.shrink_to_fit ();
3234 // Parses type generic parameters. Will also consume any trailing comma.
3235 template <typename ManagedTokenSource
>
3236 template <typename EndTokenPred
>
3237 std::vector
<std::unique_ptr
<AST::TypeParam
>>
3238 Parser
<ManagedTokenSource
>::parse_type_params (EndTokenPred is_end_token
)
3240 std::vector
<std::unique_ptr
<AST::TypeParam
>> type_params
;
3242 while (!is_end_token (lexer
.peek_token ()->get_id ()))
3244 std::unique_ptr
<AST::TypeParam
> type_param
= parse_type_param ();
3246 if (type_param
== nullptr)
3248 Error
error (lexer
.peek_token ()->get_locus (),
3249 "failed to parse type param in type params");
3250 add_error (std::move (error
));
3255 type_params
.push_back (std::move (type_param
));
3257 if (lexer
.peek_token ()->get_id () != COMMA
)
3260 // skip commas, including trailing commas
3261 lexer
.skip_token ();
3264 type_params
.shrink_to_fit ();
3266 /* TODO: this shares most code with parse_lifetime_params - good place to
3267 * use template (i.e. parse_non_ptr_sequence if doable) */
3270 /* Parses a single type (generic) parameter, not including commas. May change
3271 * to return value. */
3272 template <typename ManagedTokenSource
>
3273 std::unique_ptr
<AST::TypeParam
>
3274 Parser
<ManagedTokenSource
>::parse_type_param ()
3276 // parse outer attribute, which is optional and may not exist
3277 AST::Attribute outer_attr
= parse_outer_attribute ();
3279 const_TokenPtr identifier_tok
= lexer
.peek_token ();
3280 if (identifier_tok
->get_id () != IDENTIFIER
)
3282 // return null as type param can't exist without this required
3286 // TODO: create identifier from identifier token
3287 Identifier ident
= identifier_tok
->get_str ();
3288 lexer
.skip_token ();
3290 // parse type param bounds (if they exist)
3291 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
;
3292 if (lexer
.peek_token ()->get_id () == COLON
)
3294 lexer
.skip_token ();
3296 // parse type param bounds, which may or may not exist
3297 type_param_bounds
= parse_type_param_bounds ();
3300 // parse type (if it exists)
3301 std::unique_ptr
<AST::Type
> type
= nullptr;
3302 if (lexer
.peek_token ()->get_id () == EQUAL
)
3304 lexer
.skip_token ();
3306 // parse type (now required)
3307 type
= parse_type ();
3308 if (type
== nullptr)
3310 Error
error (lexer
.peek_token ()->get_locus (),
3311 "failed to parse type in type param");
3312 add_error (std::move (error
));
3318 return std::unique_ptr
<AST::TypeParam
> (
3319 new AST::TypeParam (std::move (ident
), identifier_tok
->get_locus (),
3320 std::move (type_param_bounds
), std::move (type
),
3321 std::move (outer_attr
)));
3324 /* Parses regular (i.e. non-generic) parameters in functions or methods. Also
3325 * has end token handling. */
3326 template <typename ManagedTokenSource
>
3327 template <typename EndTokenPred
>
3328 std::vector
<AST::FunctionParam
>
3329 Parser
<ManagedTokenSource
>::parse_function_params (EndTokenPred is_end_token
)
3331 std::vector
<AST::FunctionParam
> params
;
3333 if (is_end_token (lexer
.peek_token ()->get_id ()))
3336 AST::FunctionParam initial_param
= parse_function_param ();
3338 // Return empty parameter list if no parameter there
3339 if (initial_param
.is_error ())
3341 // TODO: is this an error?
3345 params
.push_back (std::move (initial_param
));
3347 // maybe think of a better control structure here - do-while with an initial
3348 // error state? basically, loop through parameter list until can't find any
3350 const_TokenPtr t
= lexer
.peek_token ();
3351 while (t
->get_id () == COMMA
)
3353 // skip comma if applies
3354 lexer
.skip_token ();
3356 // TODO: strictly speaking, shouldn't there be no trailing comma?
3357 if (is_end_token (lexer
.peek_token ()->get_id ()))
3360 // now, as right paren would break, function param is required
3361 AST::FunctionParam param
= parse_function_param ();
3362 if (param
.is_error ())
3364 Error
error (lexer
.peek_token ()->get_locus (),
3365 "failed to parse function param (in function params)");
3366 add_error (std::move (error
));
3369 return std::vector
<AST::FunctionParam
> ();
3372 params
.push_back (std::move (param
));
3374 t
= lexer
.peek_token ();
3377 params
.shrink_to_fit ();
3381 /* Parses a single regular (i.e. non-generic) parameter in a function or
3382 * method, i.e. the "name: type" bit. Also handles it not existing. */
3383 template <typename ManagedTokenSource
>
3385 Parser
<ManagedTokenSource
>::parse_function_param ()
3387 // parse outer attributes if they exist
3388 AST::AttrVec outer_attrs
= parse_outer_attributes ();
3390 // TODO: should saved location be at start of outer attributes or pattern?
3391 Location locus
= lexer
.peek_token ()->get_locus ();
3392 std::unique_ptr
<AST::Pattern
> param_pattern
= parse_pattern ();
3394 // create error function param if it doesn't exist
3395 if (param_pattern
== nullptr)
3397 // skip after something
3398 return AST::FunctionParam::create_error ();
3401 if (!skip_token (COLON
))
3403 // skip after something
3404 return AST::FunctionParam::create_error ();
3407 std::unique_ptr
<AST::Type
> param_type
= parse_type ();
3408 if (param_type
== nullptr)
3411 return AST::FunctionParam::create_error ();
3414 return AST::FunctionParam (std::move (param_pattern
), std::move (param_type
),
3415 std::move (outer_attrs
), locus
);
3418 /* Parses a function or method return type syntactical construction. Also
3419 * handles a function return type not existing. */
3420 template <typename ManagedTokenSource
>
3421 std::unique_ptr
<AST::Type
>
3422 Parser
<ManagedTokenSource
>::parse_function_return_type ()
3424 if (lexer
.peek_token ()->get_id () != RETURN_TYPE
)
3427 // skip return type, as it now obviously exists
3428 lexer
.skip_token ();
3430 std::unique_ptr
<AST::Type
> type
= parse_type ();
3435 /* Parses a "where clause" (in a function, struct, method, etc.). Also handles
3436 * a where clause not existing, in which it will return
3437 * WhereClause::create_empty(), which can be checked via
3438 * WhereClause::is_empty(). */
3439 template <typename ManagedTokenSource
>
3441 Parser
<ManagedTokenSource
>::parse_where_clause ()
3443 const_TokenPtr where_tok
= lexer
.peek_token ();
3444 if (where_tok
->get_id () != WHERE
)
3446 // where clause doesn't exist, so create empty one
3447 return AST::WhereClause::create_empty ();
3450 lexer
.skip_token ();
3452 /* parse where clause items - this is not a separate rule in the reference
3453 * so won't be here */
3454 std::vector
<std::unique_ptr
<AST::WhereClauseItem
>> where_clause_items
;
3456 /* HACK: where clauses end with a right curly or semicolon or equals in all
3458 const_TokenPtr t
= lexer
.peek_token ();
3459 while (t
->get_id () != LEFT_CURLY
&& t
->get_id () != SEMICOLON
3460 && t
->get_id () != EQUAL
)
3462 std::unique_ptr
<AST::WhereClauseItem
> where_clause_item
3463 = parse_where_clause_item ();
3465 if (where_clause_item
== nullptr)
3467 Error
error (t
->get_locus (), "failed to parse where clause item");
3468 add_error (std::move (error
));
3470 return AST::WhereClause::create_empty ();
3473 where_clause_items
.push_back (std::move (where_clause_item
));
3475 // also skip comma if it exists
3476 if (lexer
.peek_token ()->get_id () != COMMA
)
3479 lexer
.skip_token ();
3480 t
= lexer
.peek_token ();
3483 where_clause_items
.shrink_to_fit ();
3484 return AST::WhereClause (std::move (where_clause_items
));
3487 /* Parses a where clause item (lifetime or type bound). Does not parse any
3489 template <typename ManagedTokenSource
>
3490 std::unique_ptr
<AST::WhereClauseItem
>
3491 Parser
<ManagedTokenSource
>::parse_where_clause_item ()
3493 // shitty cheat way of determining lifetime or type bound - test for
3495 const_TokenPtr t
= lexer
.peek_token ();
3497 if (t
->get_id () == LIFETIME
)
3498 return parse_lifetime_where_clause_item ();
3500 return parse_type_bound_where_clause_item ();
3503 // Parses a lifetime where clause item.
3504 template <typename ManagedTokenSource
>
3505 std::unique_ptr
<AST::LifetimeWhereClauseItem
>
3506 Parser
<ManagedTokenSource
>::parse_lifetime_where_clause_item ()
3508 AST::Lifetime lifetime
= parse_lifetime ();
3509 if (lifetime
.is_error ())
3511 // TODO: error here?
3515 if (!skip_token (COLON
))
3517 // TODO: skip after somewhere
3521 std::vector
<AST::Lifetime
> lifetime_bounds
= parse_lifetime_bounds ();
3522 // TODO: have end token passed in?
3524 Location locus
= lifetime
.get_locus ();
3526 return std::unique_ptr
<AST::LifetimeWhereClauseItem
> (
3527 new AST::LifetimeWhereClauseItem (std::move (lifetime
),
3528 std::move (lifetime_bounds
), locus
));
3531 // Parses a type bound where clause item.
3532 template <typename ManagedTokenSource
>
3533 std::unique_ptr
<AST::TypeBoundWhereClauseItem
>
3534 Parser
<ManagedTokenSource
>::parse_type_bound_where_clause_item ()
3536 // parse for lifetimes, if it exists
3537 std::vector
<AST::LifetimeParam
> for_lifetimes
;
3538 if (lexer
.peek_token ()->get_id () == FOR
)
3539 for_lifetimes
= parse_for_lifetimes ();
3541 std::unique_ptr
<AST::Type
> type
= parse_type ();
3542 if (type
== nullptr)
3547 if (!skip_token (COLON
))
3549 // TODO: skip after somewhere
3553 // parse type param bounds if they exist
3554 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
3555 = parse_type_param_bounds ();
3557 Location locus
= lexer
.peek_token ()->get_locus ();
3559 return std::unique_ptr
<AST::TypeBoundWhereClauseItem
> (
3560 new AST::TypeBoundWhereClauseItem (std::move (for_lifetimes
),
3562 std::move (type_param_bounds
), locus
));
3565 // Parses a for lifetimes clause, including the for keyword and angle
3567 template <typename ManagedTokenSource
>
3568 std::vector
<AST::LifetimeParam
>
3569 Parser
<ManagedTokenSource
>::parse_for_lifetimes ()
3571 std::vector
<AST::LifetimeParam
> params
;
3573 if (!skip_token (FOR
))
3575 // skip after somewhere?
3579 if (!skip_token (LEFT_ANGLE
))
3581 // skip after somewhere?
3585 /* cannot specify end token due to parsing problems with '>' tokens being
3587 params
= parse_lifetime_params_objs (is_right_angle_tok
);
3589 if (!skip_generics_right_angle ())
3592 rust_debug ("failed to skip generics right angle after (supposedly) "
3593 "finished parsing where clause items");
3594 // ok, well this gets called.
3596 // skip after somewhere?
3603 // Parses type parameter bounds in where clause or generic arguments.
3604 template <typename ManagedTokenSource
>
3605 std::vector
<std::unique_ptr
<AST::TypeParamBound
>>
3606 Parser
<ManagedTokenSource
>::parse_type_param_bounds ()
3608 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
;
3610 std::unique_ptr
<AST::TypeParamBound
> initial_bound
3611 = parse_type_param_bound ();
3613 // quick exit if null
3614 if (initial_bound
== nullptr)
3616 /* error? type param bounds must have at least one term, but are bounds
3618 return type_param_bounds
;
3620 type_param_bounds
.push_back (std::move (initial_bound
));
3622 while (lexer
.peek_token ()->get_id () == PLUS
)
3624 lexer
.skip_token ();
3626 std::unique_ptr
<AST::TypeParamBound
> bound
= parse_type_param_bound ();
3627 if (bound
== nullptr)
3629 /* not an error: bound is allowed to be null as trailing plus is
3631 return type_param_bounds
;
3634 type_param_bounds
.push_back (std::move (bound
));
3637 type_param_bounds
.shrink_to_fit ();
3638 return type_param_bounds
;
3641 /* Parses type parameter bounds in where clause or generic arguments, with end
3642 * token handling. */
3643 template <typename ManagedTokenSource
>
3644 template <typename EndTokenPred
>
3645 std::vector
<std::unique_ptr
<AST::TypeParamBound
>>
3646 Parser
<ManagedTokenSource
>::parse_type_param_bounds (EndTokenPred is_end_token
)
3648 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
;
3650 std::unique_ptr
<AST::TypeParamBound
> initial_bound
3651 = parse_type_param_bound ();
3653 // quick exit if null
3654 if (initial_bound
== nullptr)
3656 /* error? type param bounds must have at least one term, but are bounds
3658 return type_param_bounds
;
3660 type_param_bounds
.push_back (std::move (initial_bound
));
3662 while (lexer
.peek_token ()->get_id () == PLUS
)
3664 lexer
.skip_token ();
3666 // break if end token character
3667 if (is_end_token (lexer
.peek_token ()->get_id ()))
3670 std::unique_ptr
<AST::TypeParamBound
> bound
= parse_type_param_bound ();
3671 if (bound
== nullptr)
3673 // TODO how wise is it to ditch all bounds if only one failed?
3674 Error
error (lexer
.peek_token ()->get_locus (),
3675 "failed to parse type param bound in type param bounds");
3676 add_error (std::move (error
));
3681 type_param_bounds
.push_back (std::move (bound
));
3684 type_param_bounds
.shrink_to_fit ();
3685 return type_param_bounds
;
3688 /* Parses a single type parameter bound in a where clause or generic argument.
3689 * Does not parse the '+' between arguments. */
3690 template <typename ManagedTokenSource
>
3691 std::unique_ptr
<AST::TypeParamBound
>
3692 Parser
<ManagedTokenSource
>::parse_type_param_bound ()
3694 // shitty cheat way of determining lifetime or trait bound - test for
3696 const_TokenPtr t
= lexer
.peek_token ();
3697 switch (t
->get_id ())
3700 return std::unique_ptr
<AST::Lifetime
> (
3701 new AST::Lifetime (parse_lifetime ()));
3711 return parse_trait_bound ();
3713 // don't error - assume this is fine TODO
3718 // Parses a trait bound type param bound.
3719 template <typename ManagedTokenSource
>
3720 std::unique_ptr
<AST::TraitBound
>
3721 Parser
<ManagedTokenSource
>::parse_trait_bound ()
3723 bool has_parens
= false;
3724 bool has_question_mark
= false;
3726 Location locus
= lexer
.peek_token ()->get_locus ();
3728 // handle trait bound being in parentheses
3729 if (lexer
.peek_token ()->get_id () == LEFT_PAREN
)
3732 lexer
.skip_token ();
3735 // handle having question mark (optional)
3736 if (lexer
.peek_token ()->get_id () == QUESTION_MARK
)
3738 has_question_mark
= true;
3739 lexer
.skip_token ();
3742 /* parse for lifetimes, if it exists (although empty for lifetimes is ok to
3744 std::vector
<AST::LifetimeParam
> for_lifetimes
;
3745 if (lexer
.peek_token ()->get_id () == FOR
)
3746 for_lifetimes
= parse_for_lifetimes ();
3749 AST::TypePath type_path
= parse_type_path ();
3751 // handle closing parentheses
3754 if (!skip_token (RIGHT_PAREN
))
3760 return std::unique_ptr
<AST::TraitBound
> (
3761 new AST::TraitBound (std::move (type_path
), locus
, has_parens
,
3762 has_question_mark
, std::move (for_lifetimes
)));
3765 // Parses lifetime bounds.
3766 template <typename ManagedTokenSource
>
3767 std::vector
<AST::Lifetime
>
3768 Parser
<ManagedTokenSource
>::parse_lifetime_bounds ()
3770 std::vector
<AST::Lifetime
> lifetime_bounds
;
3774 AST::Lifetime lifetime
= parse_lifetime ();
3776 // quick exit for parsing failure
3777 if (lifetime
.is_error ())
3780 lifetime_bounds
.push_back (std::move (lifetime
));
3782 /* plus is maybe not allowed at end - spec defines it weirdly, so
3783 * assuming allowed at end */
3784 if (lexer
.peek_token ()->get_id () != PLUS
)
3787 lexer
.skip_token ();
3790 lifetime_bounds
.shrink_to_fit ();
3791 return lifetime_bounds
;
3794 // Parses lifetime bounds, with added check for ending token.
3795 template <typename ManagedTokenSource
>
3796 template <typename EndTokenPred
>
3797 std::vector
<AST::Lifetime
>
3798 Parser
<ManagedTokenSource
>::parse_lifetime_bounds (EndTokenPred is_end_token
)
3800 std::vector
<AST::Lifetime
> lifetime_bounds
;
3802 while (!is_end_token (lexer
.peek_token ()->get_id ()))
3804 AST::Lifetime lifetime
= parse_lifetime ();
3806 if (lifetime
.is_error ())
3808 /* TODO: is it worth throwing away all lifetime bound info just
3809 * because one failed? */
3810 Error
error (lexer
.peek_token ()->get_locus (),
3811 "failed to parse lifetime in lifetime bounds");
3812 add_error (std::move (error
));
3817 lifetime_bounds
.push_back (std::move (lifetime
));
3819 /* plus is maybe not allowed at end - spec defines it weirdly, so
3820 * assuming allowed at end */
3821 if (lexer
.peek_token ()->get_id () != PLUS
)
3824 lexer
.skip_token ();
3827 lifetime_bounds
.shrink_to_fit ();
3828 return lifetime_bounds
;
3831 /* Parses a lifetime token (named, 'static, or '_). Also handles lifetime not
3833 template <typename ManagedTokenSource
>
3835 Parser
<ManagedTokenSource
>::parse_lifetime ()
3837 const_TokenPtr lifetime_tok
= lexer
.peek_token ();
3838 Location locus
= lifetime_tok
->get_locus ();
3839 // create error lifetime if doesn't exist
3840 if (lifetime_tok
->get_id () != LIFETIME
)
3842 return AST::Lifetime::error ();
3844 lexer
.skip_token ();
3846 std::string lifetime_ident
= lifetime_tok
->get_str ();
3848 if (lifetime_ident
== "'static")
3850 return AST::Lifetime (AST::Lifetime::STATIC
, "", locus
);
3852 else if (lifetime_ident
== "'_")
3854 return AST::Lifetime (AST::Lifetime::WILDCARD
, "", locus
);
3858 return AST::Lifetime (AST::Lifetime::NAMED
, std::move (lifetime_ident
),
3863 // Parses a "type alias" (typedef) item.
3864 template <typename ManagedTokenSource
>
3865 std::unique_ptr
<AST::TypeAlias
>
3866 Parser
<ManagedTokenSource
>::parse_type_alias (AST::Visibility vis
,
3867 AST::AttrVec outer_attrs
)
3869 Location locus
= lexer
.peek_token ()->get_locus ();
3872 // TODO: use this token for identifier when finished that
3873 const_TokenPtr alias_name_tok
= expect_token (IDENTIFIER
);
3874 if (alias_name_tok
== nullptr)
3876 Error
error (lexer
.peek_token ()->get_locus (),
3877 "could not parse identifier in type alias");
3878 add_error (std::move (error
));
3880 skip_after_semicolon ();
3883 Identifier alias_name
= alias_name_tok
->get_str ();
3885 // parse generic params, which may not exist
3886 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
3887 = parse_generic_params_in_angles ();
3889 // parse where clause, which may not exist
3890 AST::WhereClause where_clause
= parse_where_clause ();
3892 if (!skip_token (EQUAL
))
3894 skip_after_semicolon ();
3898 std::unique_ptr
<AST::Type
> type_to_alias
= parse_type ();
3900 if (!skip_token (SEMICOLON
))
3902 // should be skipping past this, not the next line
3906 return std::unique_ptr
<AST::TypeAlias
> (
3907 new AST::TypeAlias (std::move (alias_name
), std::move (generic_params
),
3908 std::move (where_clause
), std::move (type_to_alias
),
3909 std::move (vis
), std::move (outer_attrs
), locus
));
3912 // Parse a struct item AST node.
3913 template <typename ManagedTokenSource
>
3914 std::unique_ptr
<AST::Struct
>
3915 Parser
<ManagedTokenSource
>::parse_struct (AST::Visibility vis
,
3916 AST::AttrVec outer_attrs
)
3918 /* TODO: determine best way to parse the proper struct vs tuple struct -
3919 * share most of initial constructs so lookahead might be impossible, and if
3920 * not probably too expensive. Best way is probably unified parsing for the
3921 * initial parts and then pass them in as params to more derived functions.
3922 * Alternatively, just parse everything in this one function - do this if
3923 * function not too long. */
3925 /* Proper struct <- 'struct' IDENTIFIER generic_params? where_clause? ( '{'
3926 * struct_fields? '}' | ';' ) */
3927 /* Tuple struct <- 'struct' IDENTIFIER generic_params? '(' tuple_fields? ')'
3928 * where_clause? ';' */
3929 Location locus
= lexer
.peek_token ()->get_locus ();
3930 skip_token (STRUCT_TOK
);
3932 // parse struct name
3933 const_TokenPtr name_tok
= expect_token (IDENTIFIER
);
3934 if (name_tok
== nullptr)
3936 Error
error (lexer
.peek_token ()->get_locus (),
3937 "could not parse struct or tuple struct identifier");
3938 add_error (std::move (error
));
3940 // skip after somewhere?
3943 Identifier struct_name
= name_tok
->get_str ();
3945 // parse generic params, which may or may not exist
3946 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
3947 = parse_generic_params_in_angles ();
3949 // branch on next token - determines whether proper struct or tuple struct
3950 if (lexer
.peek_token ()->get_id () == LEFT_PAREN
)
3954 // skip left parenthesis
3955 lexer
.skip_token ();
3957 // parse tuple fields
3958 std::vector
<AST::TupleField
> tuple_fields
;
3959 // Might be empty tuple for unit tuple struct.
3960 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
3961 tuple_fields
= std::vector
<AST::TupleField
> ();
3963 tuple_fields
= parse_tuple_fields ();
3965 // tuple parameters must have closing parenthesis
3966 if (!skip_token (RIGHT_PAREN
))
3968 skip_after_semicolon ();
3972 // parse where clause, which is optional
3973 AST::WhereClause where_clause
= parse_where_clause ();
3975 if (!skip_token (SEMICOLON
))
3977 // can't skip after semicolon because it's meant to be here
3981 return std::unique_ptr
<AST::TupleStruct
> (
3982 new AST::TupleStruct (std::move (tuple_fields
), std::move (struct_name
),
3983 std::move (generic_params
),
3984 std::move (where_clause
), std::move (vis
),
3985 std::move (outer_attrs
), locus
));
3988 // assume it is a proper struct being parsed and continue outside of switch
3989 // - label only here to suppress warning
3991 // parse where clause, which is optional
3992 AST::WhereClause where_clause
= parse_where_clause ();
3994 // branch on next token - determines whether struct is a unit struct
3995 const_TokenPtr t
= lexer
.peek_token ();
3996 switch (t
->get_id ())
4001 // skip curly bracket
4002 lexer
.skip_token ();
4004 // parse struct fields, if any
4005 std::vector
<AST::StructField
> struct_fields
4006 = parse_struct_fields ([] (TokenId id
) { return id
== RIGHT_CURLY
; });
4008 if (!skip_token (RIGHT_CURLY
))
4014 return std::unique_ptr
<AST::StructStruct
> (new AST::StructStruct (
4015 std::move (struct_fields
), std::move (struct_name
),
4016 std::move (generic_params
), std::move (where_clause
), false,
4017 std::move (vis
), std::move (outer_attrs
), locus
));
4020 // unit struct declaration
4022 lexer
.skip_token ();
4024 return std::unique_ptr
<AST::StructStruct
> (
4025 new AST::StructStruct (std::move (struct_name
),
4026 std::move (generic_params
),
4027 std::move (where_clause
), std::move (vis
),
4028 std::move (outer_attrs
), locus
));
4030 add_error (Error (t
->get_locus (),
4031 "unexpected token %qs in struct declaration",
4032 t
->get_token_description ()));
4039 // Parses struct fields in struct declarations.
4040 template <typename ManagedTokenSource
>
4041 std::vector
<AST::StructField
>
4042 Parser
<ManagedTokenSource
>::parse_struct_fields ()
4044 std::vector
<AST::StructField
> fields
;
4046 AST::StructField initial_field
= parse_struct_field ();
4048 // Return empty field list if no field there
4049 if (initial_field
.is_error ())
4052 fields
.push_back (std::move (initial_field
));
4054 while (lexer
.peek_token ()->get_id () == COMMA
)
4056 lexer
.skip_token ();
4058 AST::StructField field
= parse_struct_field ();
4060 if (field
.is_error ())
4062 // would occur with trailing comma, so allowed
4066 fields
.push_back (std::move (field
));
4069 fields
.shrink_to_fit ();
4071 // TODO: template if possible (parse_non_ptr_seq)
4074 // Parses struct fields in struct declarations.
4075 template <typename ManagedTokenSource
>
4076 template <typename EndTokenPred
>
4077 std::vector
<AST::StructField
>
4078 Parser
<ManagedTokenSource
>::parse_struct_fields (EndTokenPred is_end_tok
)
4080 std::vector
<AST::StructField
> fields
;
4082 AST::StructField initial_field
= parse_struct_field ();
4084 // Return empty field list if no field there
4085 if (initial_field
.is_error ())
4088 fields
.push_back (std::move (initial_field
));
4090 while (lexer
.peek_token ()->get_id () == COMMA
)
4092 lexer
.skip_token ();
4094 if (is_end_tok (lexer
.peek_token ()->get_id ()))
4097 AST::StructField field
= parse_struct_field ();
4098 if (field
.is_error ())
4100 /* TODO: should every field be ditched just because one couldn't be
4102 Error
error (lexer
.peek_token ()->get_locus (),
4103 "failed to parse struct field in struct fields");
4104 add_error (std::move (error
));
4109 fields
.push_back (std::move (field
));
4112 fields
.shrink_to_fit ();
4114 // TODO: template if possible (parse_non_ptr_seq)
4117 // Parses a single struct field (in a struct definition). Does not parse
4119 template <typename ManagedTokenSource
>
4121 Parser
<ManagedTokenSource
>::parse_struct_field ()
4123 // parse outer attributes, if they exist
4124 AST::AttrVec outer_attrs
= parse_outer_attributes ();
4126 // parse visibility, if it exists
4127 AST::Visibility vis
= parse_visibility ();
4129 Location locus
= lexer
.peek_token ()->get_locus ();
4132 const_TokenPtr field_name_tok
= lexer
.peek_token ();
4133 if (field_name_tok
->get_id () != IDENTIFIER
)
4135 // if not identifier, assumes there is no struct field and exits - not
4136 // necessarily error
4137 return AST::StructField::create_error ();
4139 Identifier field_name
= field_name_tok
->get_str ();
4140 lexer
.skip_token ();
4142 if (!skip_token (COLON
))
4144 // skip after somewhere?
4145 return AST::StructField::create_error ();
4148 // parse field type - this is required
4149 std::unique_ptr
<AST::Type
> field_type
= parse_type ();
4150 if (field_type
== nullptr)
4152 Error
error (lexer
.peek_token ()->get_locus (),
4153 "could not parse type in struct field definition");
4154 add_error (std::move (error
));
4156 // skip after somewhere
4157 return AST::StructField::create_error ();
4160 return AST::StructField (std::move (field_name
), std::move (field_type
),
4161 std::move (vis
), locus
, std::move (outer_attrs
));
4164 // Parses tuple fields in tuple/tuple struct declarations.
4165 template <typename ManagedTokenSource
>
4166 std::vector
<AST::TupleField
>
4167 Parser
<ManagedTokenSource
>::parse_tuple_fields ()
4169 std::vector
<AST::TupleField
> fields
;
4171 AST::TupleField initial_field
= parse_tuple_field ();
4173 // Return empty field list if no field there
4174 if (initial_field
.is_error ())
4179 fields
.push_back (std::move (initial_field
));
4181 // maybe think of a better control structure here - do-while with an initial
4182 // error state? basically, loop through field list until can't find any more
4183 // params HACK: all current syntax uses of tuple fields have them ending
4184 // with a right paren token
4185 const_TokenPtr t
= lexer
.peek_token ();
4186 while (t
->get_id () == COMMA
)
4188 // skip comma if applies - e.g. trailing comma
4189 lexer
.skip_token ();
4191 // break out due to right paren if it exists
4192 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
4197 AST::TupleField field
= parse_tuple_field ();
4198 if (field
.is_error ())
4200 Error
error (lexer
.peek_token ()->get_locus (),
4201 "failed to parse tuple field in tuple fields");
4202 add_error (std::move (error
));
4204 return std::vector
<AST::TupleField
> ();
4207 fields
.push_back (std::move (field
));
4209 t
= lexer
.peek_token ();
4212 fields
.shrink_to_fit ();
4215 // TODO: this shares basically all code with function params and struct
4220 /* Parses a single tuple struct field in a tuple struct definition. Does not
4222 template <typename ManagedTokenSource
>
4224 Parser
<ManagedTokenSource
>::parse_tuple_field ()
4226 // parse outer attributes if they exist
4227 AST::AttrVec outer_attrs
= parse_outer_attributes ();
4229 // parse visibility if it exists
4230 AST::Visibility vis
= parse_visibility ();
4232 Location locus
= lexer
.peek_token ()->get_locus ();
4234 // parse type, which is required
4235 std::unique_ptr
<AST::Type
> field_type
= parse_type ();
4236 if (field_type
== nullptr)
4239 Error
error (lexer
.peek_token ()->get_locus (),
4240 "could not parse type in tuple struct field");
4241 add_error (std::move (error
));
4243 // skip after something
4244 return AST::TupleField::create_error ();
4247 return AST::TupleField (std::move (field_type
), std::move (vis
), locus
,
4248 std::move (outer_attrs
));
4251 // Parses a Rust "enum" tagged union item definition.
4252 template <typename ManagedTokenSource
>
4253 std::unique_ptr
<AST::Enum
>
4254 Parser
<ManagedTokenSource
>::parse_enum (AST::Visibility vis
,
4255 AST::AttrVec outer_attrs
)
4257 Location locus
= lexer
.peek_token ()->get_locus ();
4258 skip_token (ENUM_TOK
);
4261 const_TokenPtr enum_name_tok
= expect_token (IDENTIFIER
);
4262 if (enum_name_tok
== nullptr)
4265 Identifier enum_name
= enum_name_tok
->get_str ();
4267 // parse generic params (of enum container, not enum variants) if they exist
4268 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
4269 = parse_generic_params_in_angles ();
4271 // parse where clause if it exists
4272 AST::WhereClause where_clause
= parse_where_clause ();
4274 if (!skip_token (LEFT_CURLY
))
4276 skip_after_end_block ();
4280 // parse actual enum variant definitions
4281 std::vector
<std::unique_ptr
<AST::EnumItem
>> enum_items
4282 = parse_enum_items ([] (TokenId id
) { return id
== RIGHT_CURLY
; });
4284 if (!skip_token (RIGHT_CURLY
))
4286 skip_after_end_block ();
4290 return std::unique_ptr
<AST::Enum
> (
4291 new AST::Enum (std::move (enum_name
), std::move (vis
),
4292 std::move (generic_params
), std::move (where_clause
),
4293 std::move (enum_items
), std::move (outer_attrs
), locus
));
4296 // Parses the enum variants inside an enum definiton.
4297 template <typename ManagedTokenSource
>
4298 std::vector
<std::unique_ptr
<AST::EnumItem
>>
4299 Parser
<ManagedTokenSource
>::parse_enum_items ()
4301 std::vector
<std::unique_ptr
<AST::EnumItem
>> items
;
4303 std::unique_ptr
<AST::EnumItem
> initial_item
= parse_enum_item ();
4305 // Return empty item list if no field there
4306 if (initial_item
== nullptr)
4309 items
.push_back (std::move (initial_item
));
4311 while (lexer
.peek_token ()->get_id () == COMMA
)
4313 lexer
.skip_token ();
4315 std::unique_ptr
<AST::EnumItem
> item
= parse_enum_item ();
4316 if (item
== nullptr)
4318 // this would occur with a trailing comma, which is allowed
4322 items
.push_back (std::move (item
));
4325 items
.shrink_to_fit ();
4328 /* TODO: use template if doable (parse_non_ptr_sequence) */
4331 // Parses the enum variants inside an enum definiton.
4332 template <typename ManagedTokenSource
>
4333 template <typename EndTokenPred
>
4334 std::vector
<std::unique_ptr
<AST::EnumItem
>>
4335 Parser
<ManagedTokenSource
>::parse_enum_items (EndTokenPred is_end_tok
)
4337 std::vector
<std::unique_ptr
<AST::EnumItem
>> items
;
4339 std::unique_ptr
<AST::EnumItem
> initial_item
= parse_enum_item ();
4341 // Return empty item list if no field there
4342 if (initial_item
== nullptr)
4345 items
.push_back (std::move (initial_item
));
4347 while (lexer
.peek_token ()->get_id () == COMMA
)
4349 lexer
.skip_token ();
4351 if (is_end_tok (lexer
.peek_token ()->get_id ()))
4354 std::unique_ptr
<AST::EnumItem
> item
= parse_enum_item ();
4355 if (item
== nullptr)
4357 /* TODO should this ignore all successfully parsed enum items just
4358 * because one failed? */
4359 Error
error (lexer
.peek_token ()->get_locus (),
4360 "failed to parse enum item in enum items");
4361 add_error (std::move (error
));
4366 items
.push_back (std::move (item
));
4369 items
.shrink_to_fit ();
4372 /* TODO: use template if doable (parse_non_ptr_sequence) */
4375 /* Parses a single enum variant item in an enum definition. Does not parse
4377 template <typename ManagedTokenSource
>
4378 std::unique_ptr
<AST::EnumItem
>
4379 Parser
<ManagedTokenSource
>::parse_enum_item ()
4381 // parse outer attributes if they exist
4382 AST::AttrVec outer_attrs
= parse_outer_attributes ();
4384 // parse visibility, which may or may not exist
4385 AST::Visibility vis
= parse_visibility ();
4387 // parse name for enum item, which is required
4388 const_TokenPtr item_name_tok
= lexer
.peek_token ();
4389 if (item_name_tok
->get_id () != IDENTIFIER
)
4391 // this may not be an error but it means there is no enum item here
4394 lexer
.skip_token ();
4395 Identifier item_name
= item_name_tok
->get_str ();
4397 // branch based on next token
4398 const_TokenPtr t
= lexer
.peek_token ();
4399 switch (t
->get_id ())
4403 lexer
.skip_token ();
4405 std::vector
<AST::TupleField
> tuple_fields
;
4406 // Might be empty tuple for unit tuple enum variant.
4407 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
4408 tuple_fields
= std::vector
<AST::TupleField
> ();
4410 tuple_fields
= parse_tuple_fields ();
4412 if (!skip_token (RIGHT_PAREN
))
4414 // skip after somewhere
4418 return std::unique_ptr
<AST::EnumItemTuple
> (new AST::EnumItemTuple (
4419 std::move (item_name
), std::move (vis
), std::move (tuple_fields
),
4420 std::move (outer_attrs
), item_name_tok
->get_locus ()));
4424 lexer
.skip_token ();
4426 std::vector
<AST::StructField
> struct_fields
4427 = parse_struct_fields ([] (TokenId id
) { return id
== RIGHT_CURLY
; });
4429 if (!skip_token (RIGHT_CURLY
))
4431 // skip after somewhere
4435 return std::unique_ptr
<AST::EnumItemStruct
> (new AST::EnumItemStruct (
4436 std::move (item_name
), std::move (vis
), std::move (struct_fields
),
4437 std::move (outer_attrs
), item_name_tok
->get_locus ()));
4440 // discriminant enum item
4441 lexer
.skip_token ();
4443 std::unique_ptr
<AST::Expr
> discriminant_expr
= parse_expr ();
4445 return std::unique_ptr
<AST::EnumItemDiscriminant
> (
4446 new AST::EnumItemDiscriminant (std::move (item_name
), std::move (vis
),
4447 std::move (discriminant_expr
),
4448 std::move (outer_attrs
),
4449 item_name_tok
->get_locus ()));
4452 // regular enum with just an identifier
4453 return std::unique_ptr
<AST::EnumItem
> (
4454 new AST::EnumItem (std::move (item_name
), std::move (vis
),
4455 std::move (outer_attrs
),
4456 item_name_tok
->get_locus ()));
4460 // Parses a C-style (and C-compat) untagged union declaration.
4461 template <typename ManagedTokenSource
>
4462 std::unique_ptr
<AST::Union
>
4463 Parser
<ManagedTokenSource
>::parse_union (AST::Visibility vis
,
4464 AST::AttrVec outer_attrs
)
4466 /* hack - "weak keyword" by finding identifier called "union" (lookahead in
4468 const_TokenPtr union_keyword
= expect_token (IDENTIFIER
);
4469 rust_assert (union_keyword
->get_str () == "union");
4470 Location locus
= union_keyword
->get_locus ();
4472 // parse actual union name
4473 const_TokenPtr union_name_tok
= expect_token (IDENTIFIER
);
4474 if (union_name_tok
== nullptr)
4476 skip_after_next_block ();
4479 Identifier union_name
= union_name_tok
->get_str ();
4481 // parse optional generic parameters
4482 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
4483 = parse_generic_params_in_angles ();
4485 // parse optional where clause
4486 AST::WhereClause where_clause
= parse_where_clause ();
4488 if (!skip_token (LEFT_CURLY
))
4490 skip_after_end_block ();
4494 /* parse union inner items as "struct fields" because hey, syntax reuse.
4496 std::vector
<AST::StructField
> union_fields
4497 = parse_struct_fields ([] (TokenId id
) { return id
== RIGHT_CURLY
; });
4499 if (!skip_token (RIGHT_CURLY
))
4501 // skip after somewhere
4505 return std::unique_ptr
<AST::Union
> (
4506 new AST::Union (std::move (union_name
), std::move (vis
),
4507 std::move (generic_params
), std::move (where_clause
),
4508 std::move (union_fields
), std::move (outer_attrs
), locus
));
4511 /* Parses a "constant item" (compile-time constant to maybe "inline"
4512 * throughout the program - like constexpr). */
4513 template <typename ManagedTokenSource
>
4514 std::unique_ptr
<AST::ConstantItem
>
4515 Parser
<ManagedTokenSource
>::parse_const_item (AST::Visibility vis
,
4516 AST::AttrVec outer_attrs
)
4518 Location locus
= lexer
.peek_token ()->get_locus ();
4521 /* get constant identifier - this is either a proper identifier or the _
4523 const_TokenPtr ident_tok
= lexer
.peek_token ();
4524 // make default identifier the underscore wildcard one
4525 std::string
ident ("_");
4526 switch (ident_tok
->get_id ())
4529 ident
= ident_tok
->get_str ();
4530 lexer
.skip_token ();
4533 // do nothing - identifier is already "_"
4534 lexer
.skip_token ();
4538 Error (ident_tok
->get_locus (),
4539 "expected item name (identifier or %<_%>) in constant item "
4540 "declaration - found %qs",
4541 ident_tok
->get_token_description ()));
4543 skip_after_semicolon ();
4547 if (!skip_token (COLON
))
4549 skip_after_semicolon ();
4553 // parse constant type (required)
4554 std::unique_ptr
<AST::Type
> type
= parse_type ();
4556 if (!skip_token (EQUAL
))
4558 skip_after_semicolon ();
4562 // parse constant expression (required)
4563 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
4565 if (!skip_token (SEMICOLON
))
4571 return std::unique_ptr
<AST::ConstantItem
> (
4572 new AST::ConstantItem (std::move (ident
), std::move (vis
), std::move (type
),
4573 std::move (expr
), std::move (outer_attrs
), locus
));
4576 // Parses a "static item" (static storage item, with 'static lifetime).
4577 template <typename ManagedTokenSource
>
4578 std::unique_ptr
<AST::StaticItem
>
4579 Parser
<ManagedTokenSource
>::parse_static_item (AST::Visibility vis
,
4580 AST::AttrVec outer_attrs
)
4582 Location locus
= lexer
.peek_token ()->get_locus ();
4583 skip_token (STATIC_TOK
);
4585 // determine whether static item is mutable
4586 bool is_mut
= false;
4587 if (lexer
.peek_token ()->get_id () == MUT
)
4590 lexer
.skip_token ();
4593 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
4594 if (ident_tok
== nullptr)
4597 Identifier ident
= ident_tok
->get_str ();
4599 if (!skip_token (COLON
))
4601 skip_after_semicolon ();
4605 // parse static item type (required)
4606 std::unique_ptr
<AST::Type
> type
= parse_type ();
4608 if (!skip_token (EQUAL
))
4610 skip_after_semicolon ();
4614 // parse static item expression (required)
4615 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
4617 if (!skip_token (SEMICOLON
))
4619 // skip after somewhere
4623 return std::unique_ptr
<AST::StaticItem
> (
4624 new AST::StaticItem (std::move (ident
), is_mut
, std::move (type
),
4625 std::move (expr
), std::move (vis
),
4626 std::move (outer_attrs
), locus
));
4629 // Parses a trait definition item, including unsafe ones.
4630 template <typename ManagedTokenSource
>
4631 std::unique_ptr
<AST::Trait
>
4632 Parser
<ManagedTokenSource
>::parse_trait (AST::Visibility vis
,
4633 AST::AttrVec outer_attrs
)
4635 Location locus
= lexer
.peek_token ()->get_locus ();
4636 bool is_unsafe
= false;
4637 if (lexer
.peek_token ()->get_id () == UNSAFE
)
4640 lexer
.skip_token ();
4646 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
4647 if (ident_tok
== nullptr)
4650 Identifier ident
= ident_tok
->get_str ();
4652 // parse generic parameters (if they exist)
4653 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
4654 = parse_generic_params_in_angles ();
4656 // create placeholder type param bounds in case they don't exist
4657 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> type_param_bounds
;
4659 // parse type param bounds (if they exist)
4660 if (lexer
.peek_token ()->get_id () == COLON
)
4662 lexer
.skip_token ();
4664 type_param_bounds
= parse_type_param_bounds (
4665 [] (TokenId id
) { return id
== WHERE
|| id
== LEFT_CURLY
; });
4666 // type_param_bounds = parse_type_param_bounds ();
4669 // parse where clause (if it exists)
4670 AST::WhereClause where_clause
= parse_where_clause ();
4672 if (!skip_token (LEFT_CURLY
))
4674 skip_after_end_block ();
4678 // parse inner attrs (if they exist)
4679 AST::AttrVec inner_attrs
= parse_inner_attributes ();
4681 // parse trait items
4682 std::vector
<std::unique_ptr
<AST::TraitItem
>> trait_items
;
4684 const_TokenPtr t
= lexer
.peek_token ();
4685 while (t
->get_id () != RIGHT_CURLY
)
4687 std::unique_ptr
<AST::TraitItem
> trait_item
= parse_trait_item ();
4689 if (trait_item
== nullptr)
4691 Error
error (lexer
.peek_token ()->get_locus (),
4692 "failed to parse trait item in trait");
4693 add_error (std::move (error
));
4697 trait_items
.push_back (std::move (trait_item
));
4699 t
= lexer
.peek_token ();
4702 if (!skip_token (RIGHT_CURLY
))
4704 // skip after something
4708 trait_items
.shrink_to_fit ();
4709 return std::unique_ptr
<AST::Trait
> (
4710 new AST::Trait (std::move (ident
), is_unsafe
, std::move (generic_params
),
4711 std::move (type_param_bounds
), std::move (where_clause
),
4712 std::move (trait_items
), std::move (vis
),
4713 std::move (outer_attrs
), std::move (inner_attrs
), locus
));
4716 // Parses a trait item used inside traits (not trait, the Item).
4717 template <typename ManagedTokenSource
>
4718 std::unique_ptr
<AST::TraitItem
>
4719 Parser
<ManagedTokenSource
>::parse_trait_item ()
4721 // parse outer attributes (if they exist)
4722 AST::AttrVec outer_attrs
= parse_outer_attributes ();
4724 // lookahead to determine what type of trait item to parse
4725 const_TokenPtr tok
= lexer
.peek_token ();
4726 switch (tok
->get_id ())
4729 return parse_trait_type (std::move (outer_attrs
));
4731 // disambiguate with function qualifier
4732 if (lexer
.peek_token (1)->get_id () == IDENTIFIER
)
4734 return parse_trait_const (std::move (outer_attrs
));
4736 // else, fallthrough to function
4737 // TODO: find out how to disable gcc "implicit fallthrough" error
4742 /* function and method can't be disambiguated by lookahead alone
4743 * (without a lot of work and waste), so either make a
4744 * "parse_trait_function_or_method" or parse here mostly and pass in
4745 * most parameters (or if short enough, parse whole thing here). */
4746 // parse function and method here
4748 // parse function or method qualifiers
4749 AST::FunctionQualifiers qualifiers
= parse_function_qualifiers ();
4751 skip_token (FN_TOK
);
4753 // parse function or method name
4754 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
4755 if (ident_tok
== nullptr)
4758 Identifier ident
= ident_tok
->get_str ();
4760 // parse generic params
4761 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
4762 = parse_generic_params_in_angles ();
4764 if (!skip_token (LEFT_PAREN
))
4766 // skip after somewhere?
4770 /* now for function vs method disambiguation - method has opening
4772 AST::SelfParam self_param
= parse_self_param ();
4773 /* FIXME: ensure that self param doesn't accidently consume tokens for
4775 bool is_method
= false;
4776 if (!self_param
.is_error ())
4780 /* skip comma so function and method regular params can be parsed
4782 if (lexer
.peek_token ()->get_id () == COMMA
)
4783 lexer
.skip_token ();
4786 // parse trait function params
4787 std::vector
<AST::FunctionParam
> function_params
4788 = parse_function_params (
4789 [] (TokenId id
) { return id
== RIGHT_PAREN
; });
4791 if (!skip_token (RIGHT_PAREN
))
4793 // skip after somewhere?
4797 // parse return type (optional)
4798 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
4800 // parse where clause (optional)
4801 AST::WhereClause where_clause
= parse_where_clause ();
4803 // parse semicolon or function definition (in block)
4804 const_TokenPtr t
= lexer
.peek_token ();
4805 std::unique_ptr
<AST::BlockExpr
> definition
= nullptr;
4806 switch (t
->get_id ())
4809 lexer
.skip_token ();
4810 // definition is already nullptr, so don't need to change it
4813 definition
= parse_block_expr ();
4814 /* FIXME: are these outer attributes meant to be passed into the
4819 Error (t
->get_locus (),
4820 "expected %<;%> or definiton at the end of trait %s "
4821 "definition - found %qs instead",
4822 is_method
? "method" : "function",
4823 t
->get_token_description ()));
4829 // do actual if instead of ternary for return value optimisation
4832 AST::TraitMethodDecl
method_decl (std::move (ident
),
4833 std::move (qualifiers
),
4834 std::move (generic_params
),
4835 std::move (self_param
),
4836 std::move (function_params
),
4837 std::move (return_type
),
4838 std::move (where_clause
));
4840 // TODO: does this (method_decl) need move?
4841 return std::unique_ptr
<AST::TraitItemMethod
> (
4842 new AST::TraitItemMethod (std::move (method_decl
),
4843 std::move (definition
),
4844 std::move (outer_attrs
),
4845 tok
->get_locus ()));
4849 AST::TraitFunctionDecl
function_decl (std::move (ident
),
4850 std::move (qualifiers
),
4851 std::move (generic_params
),
4852 std::move (function_params
),
4853 std::move (return_type
),
4854 std::move (where_clause
));
4856 return std::unique_ptr
<AST::TraitItemFunc
> (new AST::TraitItemFunc (
4857 std::move (function_decl
), std::move (definition
),
4858 std::move (outer_attrs
), tok
->get_locus ()));
4862 // TODO: try and parse macro invocation semi - if fails, maybe error.
4863 std::unique_ptr
<AST::TraitItem
> macro_invoc
4864 = parse_macro_invocation_semi (outer_attrs
);
4866 if (macro_invoc
== nullptr)
4875 /* FIXME: macro invocations can only start with certain tokens. be
4876 * more picky with these? */
4881 // Parse a typedef trait item.
4882 template <typename ManagedTokenSource
>
4883 std::unique_ptr
<AST::TraitItemType
>
4884 Parser
<ManagedTokenSource
>::parse_trait_type (AST::AttrVec outer_attrs
)
4886 Location locus
= lexer
.peek_token ()->get_locus ();
4889 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
4890 if (ident_tok
== nullptr)
4893 Identifier ident
= ident_tok
->get_str ();
4895 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
4897 // parse optional colon
4898 if (lexer
.peek_token ()->get_id () == COLON
)
4900 lexer
.skip_token ();
4902 // parse optional type param bounds
4904 = parse_type_param_bounds ([] (TokenId id
) { return id
== SEMICOLON
; });
4905 // bounds = parse_type_param_bounds ();
4908 if (!skip_token (SEMICOLON
))
4914 return std::unique_ptr
<AST::TraitItemType
> (
4915 new AST::TraitItemType (std::move (ident
), std::move (bounds
),
4916 std::move (outer_attrs
), locus
));
4919 // Parses a constant trait item.
4920 template <typename ManagedTokenSource
>
4921 std::unique_ptr
<AST::TraitItemConst
>
4922 Parser
<ManagedTokenSource
>::parse_trait_const (AST::AttrVec outer_attrs
)
4924 Location locus
= lexer
.peek_token ()->get_locus ();
4927 // parse constant item name
4928 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
4929 if (ident_tok
== nullptr)
4932 Identifier ident
= ident_tok
->get_str ();
4934 if (!skip_token (COLON
))
4936 skip_after_semicolon ();
4940 // parse constant trait item type
4941 std::unique_ptr
<AST::Type
> type
= parse_type ();
4943 // parse constant trait body expression, if it exists
4944 std::unique_ptr
<AST::Expr
> const_body
= nullptr;
4945 if (lexer
.peek_token ()->get_id () == EQUAL
)
4947 lexer
.skip_token ();
4949 // expression must exist, so parse it
4950 const_body
= parse_expr ();
4953 if (!skip_token (SEMICOLON
))
4955 // skip after something?
4959 return std::unique_ptr
<AST::TraitItemConst
> (
4960 new AST::TraitItemConst (std::move (ident
), std::move (type
),
4961 std::move (const_body
), std::move (outer_attrs
),
4965 /* Parses a struct "impl" item (both inherent impl and trait impl can be
4967 template <typename ManagedTokenSource
>
4968 std::unique_ptr
<AST::Impl
>
4969 Parser
<ManagedTokenSource
>::parse_impl (AST::Visibility vis
,
4970 AST::AttrVec outer_attrs
)
4972 /* Note that only trait impls are allowed to be unsafe. So if unsafe, it
4973 * must be a trait impl. However, this isn't enough for full disambiguation,
4974 * so don't branch here. */
4975 Location locus
= lexer
.peek_token ()->get_locus ();
4976 bool is_unsafe
= false;
4977 if (lexer
.peek_token ()->get_id () == UNSAFE
)
4979 lexer
.skip_token ();
4983 if (!skip_token (IMPL
))
4985 skip_after_next_block ();
4989 // parse generic params (shared by trait and inherent impls)
4990 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
4991 = parse_generic_params_in_angles ();
4993 // Again, trait impl-only feature, but optional one, so can be used for
4995 bool has_exclam
= false;
4996 if (lexer
.peek_token ()->get_id () == EXCLAM
)
4998 lexer
.skip_token ();
5002 /* FIXME: code that doesn't look shit for TypePath. Also, make sure this
5003 * doesn't parse too much and not work. */
5004 AST::TypePath type_path
= parse_type_path ();
5005 if (type_path
.is_error () || lexer
.peek_token ()->get_id () != FOR
)
5007 /* cannot parse type path (or not for token next, at least), so must be
5010 // hacky conversion of TypePath stack object to Type pointer
5011 std::unique_ptr
<AST::Type
> type
= nullptr;
5012 if (!type_path
.is_error ())
5013 type
= std::unique_ptr
<AST::TypePath
> (
5014 new AST::TypePath (std::move (type_path
)));
5016 type
= parse_type ();
5018 // Type is required, so error if null
5019 if (type
== nullptr)
5021 Error
error (lexer
.peek_token ()->get_locus (),
5022 "could not parse type in inherent impl");
5023 add_error (std::move (error
));
5025 skip_after_next_block ();
5029 // parse optional where clause
5030 AST::WhereClause where_clause
= parse_where_clause ();
5032 if (!skip_token (LEFT_CURLY
))
5034 // TODO: does this still skip properly?
5035 skip_after_end_block ();
5039 // parse inner attributes (optional)
5040 AST::AttrVec inner_attrs
= parse_inner_attributes ();
5042 // parse inherent impl items
5043 std::vector
<std::unique_ptr
<AST::InherentImplItem
>> impl_items
;
5045 const_TokenPtr t
= lexer
.peek_token ();
5046 while (t
->get_id () != RIGHT_CURLY
)
5048 std::unique_ptr
<AST::InherentImplItem
> impl_item
5049 = parse_inherent_impl_item ();
5051 if (impl_item
== nullptr)
5054 lexer
.peek_token ()->get_locus (),
5055 "failed to parse inherent impl item in inherent impl");
5056 add_error (std::move (error
));
5061 impl_items
.push_back (std::move (impl_item
));
5063 t
= lexer
.peek_token ();
5066 if (!skip_token (RIGHT_CURLY
))
5073 rust_debug ("successfully parsed inherent impl");
5075 impl_items
.shrink_to_fit ();
5077 return std::unique_ptr
<AST::InherentImpl
> (new AST::InherentImpl (
5078 std::move (impl_items
), std::move (generic_params
), std::move (type
),
5079 std::move (where_clause
), std::move (vis
), std::move (inner_attrs
),
5080 std::move (outer_attrs
), locus
));
5084 // type path must both be valid and next token is for, so trait impl
5085 if (!skip_token (FOR
))
5087 skip_after_next_block ();
5092 std::unique_ptr
<AST::Type
> type
= parse_type ();
5093 // ensure type is included as it is required
5094 if (type
== nullptr)
5096 Error
error (lexer
.peek_token ()->get_locus (),
5097 "could not parse type in trait impl");
5098 add_error (std::move (error
));
5100 skip_after_next_block ();
5104 // parse optional where clause
5105 AST::WhereClause where_clause
= parse_where_clause ();
5107 if (!skip_token (LEFT_CURLY
))
5109 // TODO: does this still skip properly?
5110 skip_after_end_block ();
5114 // parse inner attributes (optional)
5115 AST::AttrVec inner_attrs
= parse_inner_attributes ();
5117 // parse trait impl items
5118 std::vector
<std::unique_ptr
<AST::TraitImplItem
>> impl_items
;
5120 const_TokenPtr t
= lexer
.peek_token ();
5121 while (t
->get_id () != RIGHT_CURLY
)
5123 std::unique_ptr
<AST::TraitImplItem
> impl_item
5124 = parse_trait_impl_item ();
5126 if (impl_item
== nullptr)
5128 Error
error (lexer
.peek_token ()->get_locus (),
5129 "failed to parse trait impl item in trait impl");
5130 add_error (std::move (error
));
5135 impl_items
.push_back (std::move (impl_item
));
5137 t
= lexer
.peek_token ();
5140 rust_debug ("successfully parsed a trait impl item");
5143 rust_debug ("successfully finished trait impl items");
5145 if (!skip_token (RIGHT_CURLY
))
5152 rust_debug ("successfully parsed trait impl");
5154 impl_items
.shrink_to_fit ();
5156 return std::unique_ptr
<AST::TraitImpl
> (
5157 new AST::TraitImpl (std::move (type_path
), is_unsafe
, has_exclam
,
5158 std::move (impl_items
), std::move (generic_params
),
5159 std::move (type
), std::move (where_clause
),
5160 std::move (vis
), std::move (inner_attrs
),
5161 std::move (outer_attrs
), locus
));
5165 // Parses a single inherent impl item (item inside an inherent impl block).
5166 template <typename ManagedTokenSource
>
5167 std::unique_ptr
<AST::InherentImplItem
>
5168 Parser
<ManagedTokenSource
>::parse_inherent_impl_item ()
5170 // parse outer attributes (if they exist)
5171 AST::AttrVec outer_attrs
= parse_outer_attributes ();
5173 // TODO: cleanup - currently an unreadable mess
5175 // branch on next token:
5176 const_TokenPtr t
= lexer
.peek_token ();
5177 switch (t
->get_id ())
5180 // FIXME: Arthur: Do we need to some lookahead here?
5181 return parse_macro_invocation_semi (outer_attrs
);
5186 // visibility, so not a macro invocation semi - must be constant,
5187 // function, or method
5188 AST::Visibility vis
= parse_visibility ();
5190 // TODO: is a recursive call to parse_inherent_impl_item better?
5191 switch (lexer
.peek_token ()->get_id ())
5196 // function or method
5197 return parse_inherent_impl_function_or_method (std::move (vis
),
5201 // lookahead to resolve production - could be function/method or
5203 t
= lexer
.peek_token (1);
5205 switch (t
->get_id ())
5209 return parse_const_item (std::move (vis
),
5210 std::move (outer_attrs
));
5214 return parse_inherent_impl_function_or_method (std::move (vis
),
5218 add_error (Error (t
->get_locus (),
5219 "unexpected token %qs in some sort of const "
5220 "item in inherent impl",
5221 t
->get_token_description ()));
5223 lexer
.skip_token (1); // TODO: is this right thing to do?
5228 Error (t
->get_locus (),
5229 "unrecognised token %qs for item in inherent impl",
5230 t
->get_token_description ()));
5238 // function or method
5239 return parse_inherent_impl_function_or_method (
5240 AST::Visibility::create_private (), std::move (outer_attrs
));
5242 /* lookahead to resolve production - could be function/method or const
5244 t
= lexer
.peek_token (1);
5246 switch (t
->get_id ())
5250 return parse_const_item (AST::Visibility::create_private (),
5251 std::move (outer_attrs
));
5255 return parse_inherent_impl_function_or_method (
5256 AST::Visibility::create_private (), std::move (outer_attrs
));
5258 add_error (Error (t
->get_locus (),
5259 "unexpected token %qs in some sort of const item "
5261 t
->get_token_description ()));
5263 lexer
.skip_token (1); // TODO: is this right thing to do?
5268 add_error (Error (t
->get_locus (),
5269 "unrecognised token %qs for item in inherent impl",
5270 t
->get_token_description ()));
5277 /* For internal use only by parse_inherent_impl_item() - splits giant method
5278 * into smaller ones and prevents duplication of logic. Strictly, this parses
5279 * a function or method item inside an inherent impl item block. */
5280 // TODO: make this a templated function with "return type" as type param -
5281 // InherentImplItem is this specialisation of the template while TraitImplItem
5282 // will be the other.
5283 template <typename ManagedTokenSource
>
5284 std::unique_ptr
<AST::InherentImplItem
>
5285 Parser
<ManagedTokenSource
>::parse_inherent_impl_function_or_method (
5286 AST::Visibility vis
, AST::AttrVec outer_attrs
)
5288 Location locus
= lexer
.peek_token ()->get_locus ();
5289 // parse function or method qualifiers
5290 AST::FunctionQualifiers qualifiers
= parse_function_qualifiers ();
5292 skip_token (FN_TOK
);
5294 // parse function or method name
5295 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
5296 if (ident_tok
== nullptr)
5299 Identifier ident
= ident_tok
->get_str ();
5301 // parse generic params
5302 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
5303 = parse_generic_params_in_angles ();
5305 if (!skip_token (LEFT_PAREN
))
5307 // skip after somewhere?
5311 // now for function vs method disambiguation - method has opening "self"
5313 AST::SelfParam self_param
= parse_self_param ();
5314 /* FIXME: ensure that self param doesn't accidently consume tokens for a
5315 * function one idea is to lookahead up to 4 tokens to see whether self is
5317 bool is_method
= false;
5318 if (!self_param
.is_error ())
5322 /* skip comma so function and method regular params can be parsed in
5324 if (lexer
.peek_token ()->get_id () == COMMA
)
5325 lexer
.skip_token ();
5328 // parse trait function params
5329 std::vector
<AST::FunctionParam
> function_params
5330 = parse_function_params ([] (TokenId id
) { return id
== RIGHT_PAREN
; });
5332 if (!skip_token (RIGHT_PAREN
))
5334 skip_after_end_block ();
5338 // parse return type (optional)
5339 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
5341 // parse where clause (optional)
5342 AST::WhereClause where_clause
= parse_where_clause ();
5344 // parse function definition (in block) - semicolon not allowed
5345 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
5347 Error
error (lexer
.peek_token ()->get_locus (),
5348 "%s declaration in inherent impl not allowed - must have "
5350 is_method
? "method" : "function");
5351 add_error (std::move (error
));
5353 lexer
.skip_token ();
5356 std::unique_ptr
<AST::BlockExpr
> body
= parse_block_expr ();
5357 if (body
== nullptr)
5359 Error
error (lexer
.peek_token ()->get_locus (),
5360 "could not parse definition in inherent impl %s definition",
5361 is_method
? "method" : "function");
5362 add_error (std::move (error
));
5364 skip_after_end_block ();
5368 // do actual if instead of ternary for return value optimisation
5371 return std::unique_ptr
<AST::Method
> (
5372 new AST::Method (std::move (ident
), std::move (qualifiers
),
5373 std::move (generic_params
), std::move (self_param
),
5374 std::move (function_params
), std::move (return_type
),
5375 std::move (where_clause
), std::move (body
),
5376 std::move (vis
), std::move (outer_attrs
), locus
));
5380 return std::unique_ptr
<AST::Function
> (
5381 new AST::Function (std::move (ident
), std::move (qualifiers
),
5382 std::move (generic_params
),
5383 std::move (function_params
), std::move (return_type
),
5384 std::move (where_clause
), std::move (body
),
5385 std::move (vis
), std::move (outer_attrs
), locus
));
5389 // Parses a single trait impl item (item inside a trait impl block).
5390 template <typename ManagedTokenSource
>
5391 std::unique_ptr
<AST::TraitImplItem
>
5392 Parser
<ManagedTokenSource
>::parse_trait_impl_item ()
5394 // parse outer attributes (if they exist)
5395 AST::AttrVec outer_attrs
= parse_outer_attributes ();
5397 // TODO: clean this function up, it is basically unreadable hacks
5399 // branch on next token:
5400 const_TokenPtr t
= lexer
.peek_token ();
5401 switch (t
->get_id ())
5408 // these seem to be SimplePath tokens, so this is a macro invocation
5410 return parse_macro_invocation_semi (std::move (outer_attrs
));
5412 return parse_type_alias (AST::Visibility::create_private (),
5413 std::move (outer_attrs
));
5415 // visibility, so not a macro invocation semi - must be constant,
5416 // function, or method
5417 AST::Visibility vis
= parse_visibility ();
5419 // TODO: is a recursive call to parse_trait_impl_item better?
5420 switch (lexer
.peek_token ()->get_id ())
5423 return parse_type_alias (std::move (vis
), std::move (outer_attrs
));
5427 // function or method
5428 return parse_trait_impl_function_or_method (std::move (vis
),
5432 // lookahead to resolve production - could be function/method or
5434 t
= lexer
.peek_token (1);
5436 switch (t
->get_id ())
5440 return parse_const_item (std::move (vis
),
5441 std::move (outer_attrs
));
5445 return parse_trait_impl_function_or_method (std::move (vis
),
5449 add_error (Error (t
->get_locus (),
5450 "unexpected token %qs in some sort of const "
5451 "item in trait impl",
5452 t
->get_token_description ()));
5454 lexer
.skip_token (1); // TODO: is this right thing to do?
5458 add_error (Error (t
->get_locus (),
5459 "unrecognised token %qs for item in trait impl",
5460 t
->get_token_description ()));
5469 // function or method
5470 return parse_trait_impl_function_or_method (
5471 AST::Visibility::create_private (), std::move (outer_attrs
));
5473 // lookahead to resolve production - could be function/method or const
5475 t
= lexer
.peek_token (1);
5477 switch (t
->get_id ())
5481 return parse_const_item (AST::Visibility::create_private (),
5482 std::move (outer_attrs
));
5486 return parse_trait_impl_function_or_method (
5487 AST::Visibility::create_private (), std::move (outer_attrs
));
5491 "unexpected token %qs in some sort of const item in trait impl",
5492 t
->get_token_description ()));
5494 lexer
.skip_token (1); // TODO: is this right thing to do?
5499 add_error (Error (t
->get_locus (),
5500 "unrecognised token %qs for item in trait impl",
5501 t
->get_token_description ()));
5508 /* For internal use only by parse_trait_impl_item() - splits giant method into
5509 * smaller ones and prevents duplication of logic. Strictly, this parses a
5510 * function or method item inside a trait impl item block. */
5511 template <typename ManagedTokenSource
>
5512 std::unique_ptr
<AST::TraitImplItem
>
5513 Parser
<ManagedTokenSource
>::parse_trait_impl_function_or_method (
5514 AST::Visibility vis
, AST::AttrVec outer_attrs
)
5516 // this shares virtually all logic with
5517 // parse_inherent_impl_function_or_method
5519 Location locus
= lexer
.peek_token ()->get_locus ();
5521 // parse function or method qualifiers
5522 AST::FunctionQualifiers qualifiers
= parse_function_qualifiers ();
5524 skip_token (FN_TOK
);
5526 // parse function or method name
5527 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
5528 if (ident_tok
== nullptr)
5532 Identifier ident
= ident_tok
->get_str ();
5536 "about to start parsing generic params in trait impl function or method");
5538 // parse generic params
5539 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
5540 = parse_generic_params_in_angles ();
5544 "finished parsing generic params in trait impl function or method");
5546 if (!skip_token (LEFT_PAREN
))
5548 // skip after somewhere?
5552 // now for function vs method disambiguation - method has opening "self"
5554 AST::SelfParam self_param
= parse_self_param ();
5555 // FIXME: ensure that self param doesn't accidently consume tokens for a
5557 bool is_method
= false;
5558 if (!self_param
.is_error ())
5562 // skip comma so function and method regular params can be parsed in
5564 if (lexer
.peek_token ()->get_id () == COMMA
)
5566 lexer
.skip_token ();
5570 rust_debug ("successfully parsed self param in method trait impl item");
5575 "started to parse function params in function or method trait impl item");
5577 // parse trait function params (only if next token isn't right paren)
5578 std::vector
<AST::FunctionParam
> function_params
;
5579 if (lexer
.peek_token ()->get_id () != RIGHT_PAREN
)
5582 = parse_function_params ([] (TokenId id
) { return id
== RIGHT_PAREN
; });
5584 if (function_params
.empty ())
5587 lexer
.peek_token ()->get_locus (),
5588 "failed to parse function params in trait impl %s definition",
5589 is_method
? "method" : "function");
5590 add_error (std::move (error
));
5592 skip_after_next_block ();
5598 rust_debug ("successfully parsed function params in function or method "
5601 if (!skip_token (RIGHT_PAREN
))
5603 skip_after_next_block ();
5607 // parse return type (optional)
5608 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
5612 "successfully parsed return type in function or method trait impl item");
5614 // parse where clause (optional)
5615 AST::WhereClause where_clause
= parse_where_clause ();
5619 "successfully parsed where clause in function or method trait impl item");
5621 // parse function definition (in block) - semicolon not allowed
5622 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
5625 lexer
.peek_token ()->get_locus (),
5626 "%s declaration in trait impl not allowed - must have a definition",
5627 is_method
? "method" : "function");
5628 add_error (std::move (error
));
5630 lexer
.skip_token ();
5633 std::unique_ptr
<AST::BlockExpr
> body
= parse_block_expr ();
5634 if (body
== nullptr)
5636 Error
error (lexer
.peek_token ()->get_locus (),
5637 "could not parse definition in trait impl %s definition",
5638 is_method
? "method" : "function");
5639 add_error (std::move (error
));
5641 skip_after_end_block ();
5645 // do actual if instead of ternary for return value optimisation
5648 return std::unique_ptr
<AST::Method
> (
5649 new AST::Method (std::move (ident
), std::move (qualifiers
),
5650 std::move (generic_params
), std::move (self_param
),
5651 std::move (function_params
), std::move (return_type
),
5652 std::move (where_clause
), std::move (body
),
5653 std::move (vis
), std::move (outer_attrs
), locus
));
5657 return std::unique_ptr
<AST::Function
> (
5658 new AST::Function (std::move (ident
), std::move (qualifiers
),
5659 std::move (generic_params
),
5660 std::move (function_params
), std::move (return_type
),
5661 std::move (where_clause
), std::move (body
),
5662 std::move (vis
), std::move (outer_attrs
), locus
));
5666 // Parses an extern block of declarations.
5667 template <typename ManagedTokenSource
>
5668 std::unique_ptr
<AST::ExternBlock
>
5669 Parser
<ManagedTokenSource
>::parse_extern_block (AST::Visibility vis
,
5670 AST::AttrVec outer_attrs
)
5672 Location locus
= lexer
.peek_token ()->get_locus ();
5673 skip_token (EXTERN_TOK
);
5675 // detect optional abi name
5677 const_TokenPtr next_tok
= lexer
.peek_token ();
5678 if (next_tok
->get_id () == STRING_LITERAL
)
5680 lexer
.skip_token ();
5681 abi
= next_tok
->get_str ();
5684 if (!skip_token (LEFT_CURLY
))
5686 skip_after_end_block ();
5690 AST::AttrVec inner_attrs
= parse_inner_attributes ();
5692 // parse declarations inside extern block
5693 std::vector
<std::unique_ptr
<AST::ExternalItem
>> extern_items
;
5695 const_TokenPtr t
= lexer
.peek_token ();
5696 while (t
->get_id () != RIGHT_CURLY
)
5698 std::unique_ptr
<AST::ExternalItem
> extern_item
= parse_external_item ();
5700 if (extern_item
== nullptr)
5702 Error
error (t
->get_locus (),
5703 "failed to parse external item despite not reaching "
5704 "end of extern block");
5705 add_error (std::move (error
));
5710 extern_items
.push_back (std::move (extern_item
));
5712 t
= lexer
.peek_token ();
5715 if (!skip_token (RIGHT_CURLY
))
5721 extern_items
.shrink_to_fit ();
5723 return std::unique_ptr
<AST::ExternBlock
> (
5724 new AST::ExternBlock (std::move (abi
), std::move (extern_items
),
5725 std::move (vis
), std::move (inner_attrs
),
5726 std::move (outer_attrs
), locus
));
5729 // Parses a single extern block item (static or function declaration).
5730 template <typename ManagedTokenSource
>
5731 std::unique_ptr
<AST::ExternalItem
>
5732 Parser
<ManagedTokenSource
>::parse_external_item ()
5734 // parse optional outer attributes
5735 AST::AttrVec outer_attrs
= parse_outer_attributes ();
5737 Location locus
= lexer
.peek_token ()->get_locus ();
5739 // parse optional visibility
5740 AST::Visibility vis
= parse_visibility ();
5742 const_TokenPtr t
= lexer
.peek_token ();
5743 switch (t
->get_id ())
5746 return parse_macro_invocation_semi (outer_attrs
);
5748 // parse extern static item
5749 lexer
.skip_token ();
5751 // parse mut (optional)
5752 bool has_mut
= false;
5753 if (lexer
.peek_token ()->get_id () == MUT
)
5755 lexer
.skip_token ();
5760 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
5761 if (ident_tok
== nullptr)
5763 skip_after_semicolon ();
5766 Identifier ident
= ident_tok
->get_str ();
5768 if (!skip_token (COLON
))
5770 skip_after_semicolon ();
5774 // parse type (required)
5775 std::unique_ptr
<AST::Type
> type
= parse_type ();
5776 if (type
== nullptr)
5778 Error
error (lexer
.peek_token ()->get_locus (),
5779 "failed to parse type in external static item");
5780 add_error (std::move (error
));
5782 skip_after_semicolon ();
5786 if (!skip_token (SEMICOLON
))
5788 // skip after somewhere?
5792 return std::unique_ptr
<AST::ExternalStaticItem
> (
5793 new AST::ExternalStaticItem (std::move (ident
), std::move (type
),
5794 has_mut
, std::move (vis
),
5795 std::move (outer_attrs
), locus
));
5798 // parse extern function declaration item
5799 // skip function token
5800 lexer
.skip_token ();
5803 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
5804 if (ident_tok
== nullptr)
5806 skip_after_semicolon ();
5809 Identifier ident
= ident_tok
->get_str ();
5811 // parse (optional) generic params
5812 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
5813 = parse_generic_params_in_angles ();
5815 if (!skip_token (LEFT_PAREN
))
5817 skip_after_semicolon ();
5822 std::vector
<AST::NamedFunctionParam
> function_params
;
5823 bool is_variadic
= false;
5824 AST::AttrVec variadic_attrs
;
5826 const_TokenPtr t
= lexer
.peek_token ();
5827 while (t
->get_id () != RIGHT_PAREN
)
5829 AST::AttrVec maybe_variadic_attrs
= parse_outer_attributes ();
5830 if (lexer
.peek_token ()->get_id () == ELLIPSIS
)
5832 // variadic - use attrs for this
5833 lexer
.skip_token ();
5835 variadic_attrs
= std::move (maybe_variadic_attrs
);
5836 t
= lexer
.peek_token ();
5838 if (t
->get_id () != RIGHT_PAREN
)
5840 Error
error (t
->get_locus (),
5841 "expected right parentheses after variadic in "
5843 "parameters, found %qs",
5844 t
->get_token_description ());
5845 add_error (std::move (error
));
5847 skip_after_semicolon ();
5854 AST::NamedFunctionParam param
5855 = parse_named_function_param (std::move (maybe_variadic_attrs
));
5856 if (param
.is_error ())
5858 Error
error (t
->get_locus (), "could not parse named function "
5859 "parameter in external function");
5860 add_error (std::move (error
));
5862 skip_after_semicolon ();
5865 function_params
.push_back (std::move (param
));
5867 if (lexer
.peek_token ()->get_id () != COMMA
)
5871 lexer
.skip_token ();
5872 t
= lexer
.peek_token ();
5875 if (!skip_token (RIGHT_PAREN
))
5877 skip_after_semicolon ();
5881 // parse (optional) return type
5882 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
5884 // parse (optional) where clause
5885 AST::WhereClause where_clause
= parse_where_clause ();
5887 if (!skip_token (SEMICOLON
))
5893 function_params
.shrink_to_fit ();
5895 return std::unique_ptr
<AST::ExternalFunctionItem
> (
5896 new AST::ExternalFunctionItem (
5897 std::move (ident
), std::move (generic_params
),
5898 std::move (return_type
), std::move (where_clause
),
5899 std::move (function_params
), is_variadic
,
5900 std::move (variadic_attrs
), std::move (vis
),
5901 std::move (outer_attrs
), locus
));
5906 Error (t
->get_locus (),
5907 "unrecognised token %qs in extern block item declaration",
5908 t
->get_token_description ()));
5910 skip_after_semicolon ();
5915 /* Parses an extern block function param (with "pattern" being _ or an
5917 template <typename ManagedTokenSource
>
5918 AST::NamedFunctionParam
5919 Parser
<ManagedTokenSource
>::parse_named_function_param (
5920 AST::AttrVec outer_attrs
)
5922 // parse identifier/_
5925 const_TokenPtr t
= lexer
.peek_token ();
5926 Location name_location
= t
->get_locus ();
5927 switch (t
->get_id ())
5930 name
= t
->get_str ();
5931 lexer
.skip_token ();
5935 lexer
.skip_token ();
5938 // this is not a function param, but not necessarily an error
5939 return AST::NamedFunctionParam::create_error ();
5942 if (!skip_token (COLON
))
5944 // skip after somewhere?
5945 return AST::NamedFunctionParam::create_error ();
5948 // parse (required) type
5949 std::unique_ptr
<AST::Type
> param_type
= parse_type ();
5950 if (param_type
== nullptr)
5953 lexer
.peek_token ()->get_locus (),
5954 "could not parse param type in extern block function declaration");
5955 add_error (std::move (error
));
5957 skip_after_semicolon ();
5958 return AST::NamedFunctionParam::create_error ();
5961 return AST::NamedFunctionParam (std::move (name
), std::move (param_type
),
5962 std::move (outer_attrs
), name_location
);
5965 // Parses a statement (will further disambiguate any statement).
5966 template <typename ManagedTokenSource
>
5967 std::unique_ptr
<AST::Stmt
>
5968 Parser
<ManagedTokenSource
>::parse_stmt (ParseRestrictions restrictions
)
5970 // quick exit for empty statement
5971 // FIXME: Can we have empty statements without semicolons? Just nothing?
5972 const_TokenPtr t
= lexer
.peek_token ();
5973 if (t
->get_id () == SEMICOLON
)
5975 lexer
.skip_token ();
5976 return std::unique_ptr
<AST::EmptyStmt
> (
5977 new AST::EmptyStmt (t
->get_locus ()));
5980 // parse outer attributes
5981 AST::AttrVec outer_attrs
= parse_outer_attributes ();
5983 // parsing this will be annoying because of the many different possibilities
5984 /* best may be just to copy paste in parse_item switch, and failing that try
5985 * to parse outer attributes, and then pass them in to either a let
5986 * statement or (fallback) expression statement. */
5987 // FIXME: think of a way to do this without such a large switch?
5988 t
= lexer
.peek_token ();
5989 switch (t
->get_id ())
5993 return parse_let_stmt (std::move (outer_attrs
), restrictions
);
6006 /* TODO: implement union keyword but not really because of
6007 * context-dependence crappy hack way to parse a union written below to
6008 * separate it from the good code. */
6010 case UNSAFE
: // maybe - unsafe traits are a thing
6011 /* if any of these (should be all possible VisItem prefixes), parse a
6012 * VisItem can't parse item because would require reparsing outer
6014 return parse_vis_item (std::move (outer_attrs
));
6020 // almost certainly macro invocation semi
6021 return parse_macro_item (std::move (outer_attrs
));
6023 // crappy hack to do union "keyword"
6025 if (t
->get_str () == "union"
6026 && lexer
.peek_token (1)->get_id () == IDENTIFIER
)
6028 return parse_vis_item (std::move (outer_attrs
));
6029 // or should this go straight to parsing union?
6031 else if (t
->get_str () == "macro_rules")
6033 // macro_rules! macro item
6034 return parse_macro_item (std::move (outer_attrs
));
6036 else if (lexer
.peek_token (1)->get_id () == SCOPE_RESOLUTION
6037 || lexer
.peek_token (1)->get_id () == EXCLAM
)
6039 // FIXME: ensure doesn't take any expressions by mistake
6040 /* path (probably) or macro invocation, so probably a macro
6041 * invocation semi */
6042 return parse_macro_item (std::move (outer_attrs
));
6045 // TODO: find out how to disable gcc "implicit fallthrough" warning
6047 // fallback: expression statement
6048 return parse_expr_stmt (std::move (outer_attrs
), restrictions
);
6053 // Parses a let statement.
6054 template <typename ManagedTokenSource
>
6055 std::unique_ptr
<AST::LetStmt
>
6056 Parser
<ManagedTokenSource
>::parse_let_stmt (AST::AttrVec outer_attrs
,
6057 ParseRestrictions restrictions
)
6059 Location locus
= lexer
.peek_token ()->get_locus ();
6062 // parse pattern (required)
6063 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
6064 if (pattern
== nullptr)
6066 Error
error (lexer
.peek_token ()->get_locus (),
6067 "failed to parse pattern in let statement");
6068 add_error (std::move (error
));
6070 skip_after_semicolon ();
6074 // parse type declaration (optional)
6075 std::unique_ptr
<AST::Type
> type
= nullptr;
6076 if (lexer
.peek_token ()->get_id () == COLON
)
6078 // must have a type declaration
6079 lexer
.skip_token ();
6081 type
= parse_type ();
6082 if (type
== nullptr)
6084 Error
error (lexer
.peek_token ()->get_locus (),
6085 "failed to parse type in let statement");
6086 add_error (std::move (error
));
6088 skip_after_semicolon ();
6093 // parse expression to set variable to (optional)
6094 std::unique_ptr
<AST::Expr
> expr
= nullptr;
6095 if (lexer
.peek_token ()->get_id () == EQUAL
)
6097 // must have an expression
6098 lexer
.skip_token ();
6100 expr
= parse_expr ();
6101 if (expr
== nullptr)
6103 Error
error (lexer
.peek_token ()->get_locus (),
6104 "failed to parse expression in let statement");
6105 add_error (std::move (error
));
6107 skip_after_semicolon ();
6112 if (restrictions
.consume_semi
)
6113 if (!skip_token (SEMICOLON
))
6116 return std::unique_ptr
<AST::LetStmt
> (
6117 new AST::LetStmt (std::move (pattern
), std::move (expr
), std::move (type
),
6118 std::move (outer_attrs
), locus
));
6121 // Parses a type path.
6122 template <typename ManagedTokenSource
>
6124 Parser
<ManagedTokenSource
>::parse_type_path ()
6126 bool has_opening_scope_resolution
= false;
6127 Location locus
= lexer
.peek_token ()->get_locus ();
6128 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
)
6130 has_opening_scope_resolution
= true;
6131 lexer
.skip_token ();
6134 // create segment vector
6135 std::vector
<std::unique_ptr
<AST::TypePathSegment
>> segments
;
6137 // parse required initial segment
6138 std::unique_ptr
<AST::TypePathSegment
> initial_segment
6139 = parse_type_path_segment ();
6140 if (initial_segment
== nullptr)
6142 // skip after somewhere?
6143 // don't necessarily throw error but yeah
6144 return AST::TypePath::create_error ();
6146 segments
.push_back (std::move (initial_segment
));
6148 // parse optional segments (as long as scope resolution operator exists)
6149 const_TokenPtr t
= lexer
.peek_token ();
6150 while (t
->get_id () == SCOPE_RESOLUTION
)
6152 // skip scope resolution operator
6153 lexer
.skip_token ();
6155 // parse the actual segment - it is an error if it doesn't exist now
6156 std::unique_ptr
<AST::TypePathSegment
> segment
6157 = parse_type_path_segment ();
6158 if (segment
== nullptr)
6160 // skip after somewhere?
6161 Error
error (t
->get_locus (), "could not parse type path segment");
6162 add_error (std::move (error
));
6164 return AST::TypePath::create_error ();
6167 segments
.push_back (std::move (segment
));
6169 t
= lexer
.peek_token ();
6172 segments
.shrink_to_fit ();
6174 return AST::TypePath (std::move (segments
), locus
,
6175 has_opening_scope_resolution
);
6178 template <typename ManagedTokenSource
>
6180 Parser
<ManagedTokenSource
>::parse_generic_arg ()
6182 auto tok
= lexer
.peek_token ();
6183 std::unique_ptr
<AST::Expr
> expr
= nullptr;
6185 switch (tok
->get_id ())
6188 // This is a bit of a weird situation: With an identifier token, we
6189 // could either have a valid type or a macro (FIXME: anything else?). So
6190 // we need one bit of lookahead to differentiate if this is really
6191 auto next_tok
= lexer
.peek_token (1);
6192 if (next_tok
->get_id () == EXCLAM
)
6194 auto type
= parse_type ();
6196 return AST::GenericArg::create_type (std::move (type
));
6198 return AST::GenericArg::create_error ();
6200 lexer
.skip_token ();
6201 return AST::GenericArg::create_ambiguous (tok
->get_str (),
6205 expr
= parse_block_expr ();
6208 case STRING_LITERAL
:
6214 expr
= parse_literal_expr ();
6216 // FIXME: Because of this, error reporting is garbage for const generic
6217 // parameter's default values
6219 auto type
= parse_type ();
6220 // FIXME: Find a better way to do this?
6222 return AST::GenericArg::create_type (std::move (type
));
6224 return AST::GenericArg::create_error ();
6229 return AST::GenericArg::create_error ();
6231 return AST::GenericArg::create_const (std::move (expr
));
6234 // Parses the generic arguments in each path segment.
6235 template <typename ManagedTokenSource
>
6237 Parser
<ManagedTokenSource
>::parse_path_generic_args ()
6239 if (!skip_token (LEFT_ANGLE
))
6241 // skip after somewhere?
6242 return AST::GenericArgs::create_empty ();
6245 // We need to parse all lifetimes, then parse types and const generics in
6248 // try to parse lifetimes first
6249 std::vector
<AST::Lifetime
> lifetime_args
;
6251 const_TokenPtr t
= lexer
.peek_token ();
6252 Location locus
= t
->get_locus ();
6253 while (!is_right_angle_tok (t
->get_id ()))
6255 AST::Lifetime lifetime
= parse_lifetime ();
6256 if (lifetime
.is_error ())
6258 // not necessarily an error
6262 lifetime_args
.push_back (std::move (lifetime
));
6264 // if next token isn't comma, then it must be end of list
6265 if (lexer
.peek_token ()->get_id () != COMMA
)
6270 lexer
.skip_token ();
6272 t
= lexer
.peek_token ();
6275 // try to parse types and const generics second
6276 std::vector
<AST::GenericArg
> generic_args
;
6278 // TODO: think of better control structure
6279 t
= lexer
.peek_token ();
6280 while (!is_right_angle_tok (t
->get_id ()))
6282 // FIXME: Is it fine to break if there is one binding? Can't there be
6283 // bindings in between types?
6285 // ensure not binding being parsed as type accidently
6286 if (t
->get_id () == IDENTIFIER
6287 && lexer
.peek_token (1)->get_id () == EQUAL
)
6290 auto arg
= parse_generic_arg ();
6291 if (!arg
.is_error ())
6293 generic_args
.emplace_back (std::move (arg
));
6296 // FIXME: Do we need to break if we encounter an error?
6298 // if next token isn't comma, then it must be end of list
6299 if (lexer
.peek_token ()->get_id () != COMMA
)
6303 lexer
.skip_token ();
6304 t
= lexer
.peek_token ();
6307 // try to parse bindings third
6308 std::vector
<AST::GenericArgsBinding
> binding_args
;
6310 // TODO: think of better control structure
6311 t
= lexer
.peek_token ();
6312 while (!is_right_angle_tok (t
->get_id ()))
6314 AST::GenericArgsBinding binding
= parse_generic_args_binding ();
6315 if (binding
.is_error ())
6317 // not necessarily an error
6321 binding_args
.push_back (std::move (binding
));
6323 // if next token isn't comma, then it must be end of list
6324 if (lexer
.peek_token ()->get_id () != COMMA
)
6329 lexer
.skip_token ();
6331 t
= lexer
.peek_token ();
6334 // skip any trailing commas
6335 if (lexer
.peek_token ()->get_id () == COMMA
)
6336 lexer
.skip_token ();
6338 if (!skip_generics_right_angle ())
6339 return AST::GenericArgs::create_empty ();
6341 lifetime_args
.shrink_to_fit ();
6342 generic_args
.shrink_to_fit ();
6343 binding_args
.shrink_to_fit ();
6345 return AST::GenericArgs (std::move (lifetime_args
), std::move (generic_args
),
6346 std::move (binding_args
), locus
);
6349 // Parses a binding in a generic args path segment.
6350 template <typename ManagedTokenSource
>
6351 AST::GenericArgsBinding
6352 Parser
<ManagedTokenSource
>::parse_generic_args_binding ()
6354 const_TokenPtr ident_tok
= lexer
.peek_token ();
6355 if (ident_tok
->get_id () != IDENTIFIER
)
6357 // allow non error-inducing use
6359 return AST::GenericArgsBinding::create_error ();
6361 lexer
.skip_token ();
6362 Identifier ident
= ident_tok
->get_str ();
6364 if (!skip_token (EQUAL
))
6366 // skip after somewhere?
6367 return AST::GenericArgsBinding::create_error ();
6370 // parse type (required)
6371 std::unique_ptr
<AST::Type
> type
= parse_type ();
6372 if (type
== nullptr)
6375 return AST::GenericArgsBinding::create_error ();
6378 return AST::GenericArgsBinding (std::move (ident
), std::move (type
),
6379 ident_tok
->get_locus ());
6382 /* Parses a single type path segment (not including opening scope resolution,
6383 * but includes any internal ones). Includes generic args or type path
6385 template <typename ManagedTokenSource
>
6386 std::unique_ptr
<AST::TypePathSegment
>
6387 Parser
<ManagedTokenSource
>::parse_type_path_segment ()
6389 Location locus
= lexer
.peek_token ()->get_locus ();
6390 // parse ident segment part
6391 AST::PathIdentSegment ident_segment
= parse_path_ident_segment ();
6392 if (ident_segment
.is_error ())
6394 // not necessarily an error
6398 /* lookahead to determine if variants exist - only consume scope resolution
6400 bool has_separating_scope_resolution
= false;
6401 const_TokenPtr next
= lexer
.peek_token (1);
6402 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
6403 && (next
->get_id () == LEFT_ANGLE
|| next
->get_id () == LEFT_PAREN
))
6405 has_separating_scope_resolution
= true;
6406 lexer
.skip_token ();
6409 // branch into variants on next token
6410 const_TokenPtr t
= lexer
.peek_token ();
6411 switch (t
->get_id ())
6414 // parse generic args
6415 AST::GenericArgs generic_args
= parse_path_generic_args ();
6417 return std::unique_ptr
<AST::TypePathSegmentGeneric
> (
6418 new AST::TypePathSegmentGeneric (std::move (ident_segment
),
6419 has_separating_scope_resolution
,
6420 std::move (generic_args
), locus
));
6423 // parse type path function
6424 AST::TypePathFunction type_path_function
6425 = parse_type_path_function (locus
);
6427 if (type_path_function
.is_error ())
6429 // skip after somewhere?
6433 return std::unique_ptr
<AST::TypePathSegmentFunction
> (
6434 new AST::TypePathSegmentFunction (std::move (ident_segment
),
6435 has_separating_scope_resolution
,
6436 std::move (type_path_function
),
6441 return std::unique_ptr
<AST::TypePathSegment
> (
6442 new AST::TypePathSegment (std::move (ident_segment
),
6443 has_separating_scope_resolution
, locus
));
6448 // Parses a function call representation inside a type path.
6449 template <typename ManagedTokenSource
>
6450 AST::TypePathFunction
6451 Parser
<ManagedTokenSource
>::parse_type_path_function (Location id_location
)
6453 if (!skip_token (LEFT_PAREN
))
6456 return AST::TypePathFunction::create_error ();
6459 // parse function inputs
6460 std::vector
<std::unique_ptr
<AST::Type
>> inputs
;
6462 while (lexer
.peek_token ()->get_id () != RIGHT_PAREN
)
6464 std::unique_ptr
<AST::Type
> type
= parse_type ();
6465 if (type
== nullptr)
6467 /* this is an error as there should've been a ')' there if there
6470 lexer
.peek_token ()->get_locus (),
6471 "failed to parse type in parameters of type path function");
6472 add_error (std::move (error
));
6475 return AST::TypePathFunction::create_error ();
6478 inputs
.push_back (std::move (type
));
6480 // skip commas, including trailing commas
6481 if (lexer
.peek_token ()->get_id () != COMMA
)
6484 lexer
.skip_token ();
6487 if (!skip_token (RIGHT_PAREN
))
6490 return AST::TypePathFunction::create_error ();
6493 // parse optional return type
6494 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
6496 inputs
.shrink_to_fit ();
6497 return AST::TypePathFunction (std::move (inputs
), id_location
,
6498 std::move (return_type
));
6501 // Parses a path inside an expression that allows generic arguments.
6502 template <typename ManagedTokenSource
>
6503 AST::PathInExpression
6504 Parser
<ManagedTokenSource
>::parse_path_in_expression ()
6506 Location locus
= Linemap::unknown_location ();
6507 bool has_opening_scope_resolution
= false;
6508 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
)
6510 has_opening_scope_resolution
= true;
6512 locus
= lexer
.peek_token ()->get_locus ();
6514 lexer
.skip_token ();
6517 // create segment vector
6518 std::vector
<AST::PathExprSegment
> segments
;
6520 if (locus
== Linemap::unknown_location ())
6522 locus
= lexer
.peek_token ()->get_locus ();
6525 // parse required initial segment
6526 AST::PathExprSegment initial_segment
= parse_path_expr_segment ();
6527 if (initial_segment
.is_error ())
6529 // skip after somewhere?
6530 // don't necessarily throw error but yeah
6531 return AST::PathInExpression::create_error ();
6533 segments
.push_back (std::move (initial_segment
));
6535 // parse optional segments (as long as scope resolution operator exists)
6536 const_TokenPtr t
= lexer
.peek_token ();
6537 while (t
->get_id () == SCOPE_RESOLUTION
)
6539 // skip scope resolution operator
6540 lexer
.skip_token ();
6542 // parse the actual segment - it is an error if it doesn't exist now
6543 AST::PathExprSegment segment
= parse_path_expr_segment ();
6544 if (segment
.is_error ())
6546 // skip after somewhere?
6547 Error
error (t
->get_locus (),
6548 "could not parse path expression segment");
6549 add_error (std::move (error
));
6551 return AST::PathInExpression::create_error ();
6554 segments
.push_back (std::move (segment
));
6556 t
= lexer
.peek_token ();
6559 segments
.shrink_to_fit ();
6561 return AST::PathInExpression (std::move (segments
), {}, locus
,
6562 has_opening_scope_resolution
);
6565 /* Parses a single path in expression path segment (including generic
6567 template <typename ManagedTokenSource
>
6568 AST::PathExprSegment
6569 Parser
<ManagedTokenSource
>::parse_path_expr_segment ()
6571 Location locus
= lexer
.peek_token ()->get_locus ();
6572 // parse ident segment
6573 AST::PathIdentSegment ident
= parse_path_ident_segment ();
6574 if (ident
.is_error ())
6576 // not necessarily an error?
6577 return AST::PathExprSegment::create_error ();
6580 // parse generic args (and turbofish), if they exist
6581 /* use lookahead to determine if they actually exist (don't want to
6582 * accidently parse over next ident segment) */
6583 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
6584 && lexer
.peek_token (1)->get_id () == LEFT_ANGLE
)
6586 // skip scope resolution
6587 lexer
.skip_token ();
6589 AST::GenericArgs generic_args
= parse_path_generic_args ();
6591 return AST::PathExprSegment (std::move (ident
), locus
,
6592 std::move (generic_args
));
6595 // return a generic parameter-less expr segment if not found
6596 return AST::PathExprSegment (std::move (ident
), locus
);
6599 /* Parses a fully qualified path in expression (i.e. a pattern). FIXME does
6600 * not parse outer attrs. */
6601 template <typename ManagedTokenSource
>
6602 AST::QualifiedPathInExpression
6603 Parser
<ManagedTokenSource
>::parse_qualified_path_in_expression (
6604 Location pratt_parsed_loc
)
6606 /* Note: the Rust grammar is defined in such a way that it is impossible to
6607 * determine whether a prospective qualified path is a
6608 * QualifiedPathInExpression or QualifiedPathInType in all cases by the
6609 * rules themselves (the only possible difference is a TypePathSegment with
6610 * function, and lookahead to find this is too difficult). However, as this
6611 * is a pattern and QualifiedPathInType is a type, I believe it that their
6612 * construction will not be confused (due to rules regarding patterns vs
6614 * As such, this function will not attempt to minimise errors created by
6615 * their confusion. */
6617 // parse the qualified path type (required)
6618 AST::QualifiedPathType qual_path_type
6619 = parse_qualified_path_type (pratt_parsed_loc
);
6620 if (qual_path_type
.is_error ())
6622 // TODO: should this create a parse error?
6623 return AST::QualifiedPathInExpression::create_error ();
6625 Location locus
= qual_path_type
.get_locus ();
6627 // parse path segments
6628 std::vector
<AST::PathExprSegment
> segments
;
6630 // parse initial required segment
6631 if (!expect_token (SCOPE_RESOLUTION
))
6633 // skip after somewhere?
6635 return AST::QualifiedPathInExpression::create_error ();
6637 AST::PathExprSegment initial_segment
= parse_path_expr_segment ();
6638 if (initial_segment
.is_error ())
6640 // skip after somewhere?
6641 Error
error (lexer
.peek_token ()->get_locus (),
6642 "required initial path expression segment in "
6643 "qualified path in expression could not be parsed");
6644 add_error (std::move (error
));
6646 return AST::QualifiedPathInExpression::create_error ();
6648 segments
.push_back (std::move (initial_segment
));
6650 // parse optional segments (as long as scope resolution operator exists)
6651 const_TokenPtr t
= lexer
.peek_token ();
6652 while (t
->get_id () == SCOPE_RESOLUTION
)
6654 // skip scope resolution operator
6655 lexer
.skip_token ();
6657 // parse the actual segment - it is an error if it doesn't exist now
6658 AST::PathExprSegment segment
= parse_path_expr_segment ();
6659 if (segment
.is_error ())
6661 // skip after somewhere?
6662 Error
error (t
->get_locus (),
6663 "could not parse path expression segment in qualified "
6664 "path in expression");
6665 add_error (std::move (error
));
6667 return AST::QualifiedPathInExpression::create_error ();
6670 segments
.push_back (std::move (segment
));
6672 t
= lexer
.peek_token ();
6675 segments
.shrink_to_fit ();
6677 // FIXME: outer attr parsing
6678 return AST::QualifiedPathInExpression (std::move (qual_path_type
),
6679 std::move (segments
), {}, locus
);
6682 // Parses the type syntactical construction at the start of a qualified path.
6683 template <typename ManagedTokenSource
>
6684 AST::QualifiedPathType
6685 Parser
<ManagedTokenSource
>::parse_qualified_path_type (
6686 Location pratt_parsed_loc
)
6688 Location locus
= pratt_parsed_loc
;
6689 /* TODO: should this actually be error? is there anywhere where this could
6691 if (locus
== Linemap::unknown_location ())
6693 locus
= lexer
.peek_token ()->get_locus ();
6694 if (!skip_token (LEFT_ANGLE
))
6696 // skip after somewhere?
6697 return AST::QualifiedPathType::create_error ();
6701 // parse type (required)
6702 std::unique_ptr
<AST::Type
> type
= parse_type ();
6703 if (type
== nullptr)
6705 Error
error (lexer
.peek_token ()->get_locus (),
6706 "could not parse type in qualified path type");
6707 add_error (std::move (error
));
6710 return AST::QualifiedPathType::create_error ();
6713 // parse optional as clause
6714 AST::TypePath as_type_path
= AST::TypePath::create_error ();
6715 if (lexer
.peek_token ()->get_id () == AS
)
6717 lexer
.skip_token ();
6719 // parse type path, which is required now
6720 as_type_path
= parse_type_path ();
6721 if (as_type_path
.is_error ())
6724 lexer
.peek_token ()->get_locus (),
6725 "could not parse type path in as clause in qualified path type");
6726 add_error (std::move (error
));
6729 return AST::QualifiedPathType::create_error ();
6733 /* NOTE: should actually be a right-angle token, so
6734 * skip_generics_right_angle shouldn't be required */
6735 if (!skip_token (RIGHT_ANGLE
))
6737 // skip after somewhere?
6738 return AST::QualifiedPathType::create_error ();
6741 return AST::QualifiedPathType (std::move (type
), locus
,
6742 std::move (as_type_path
));
6745 // Parses a fully qualified path in type (i.e. a type).
6746 template <typename ManagedTokenSource
>
6747 AST::QualifiedPathInType
6748 Parser
<ManagedTokenSource
>::parse_qualified_path_in_type ()
6750 Location locus
= lexer
.peek_token ()->get_locus ();
6751 // parse the qualified path type (required)
6752 AST::QualifiedPathType qual_path_type
= parse_qualified_path_type ();
6753 if (qual_path_type
.is_error ())
6755 // TODO: should this create a parse error?
6756 return AST::QualifiedPathInType::create_error ();
6759 // parse initial required segment
6760 if (!expect_token (SCOPE_RESOLUTION
))
6762 // skip after somewhere?
6764 return AST::QualifiedPathInType::create_error ();
6766 std::unique_ptr
<AST::TypePathSegment
> initial_segment
6767 = parse_type_path_segment ();
6768 if (initial_segment
== nullptr)
6770 // skip after somewhere?
6771 Error
error (lexer
.peek_token ()->get_locus (),
6772 "required initial type path segment in qualified path in "
6773 "type could not be parsed");
6774 add_error (std::move (error
));
6776 return AST::QualifiedPathInType::create_error ();
6779 // parse optional segments (as long as scope resolution operator exists)
6780 std::vector
<std::unique_ptr
<AST::TypePathSegment
>> segments
;
6781 const_TokenPtr t
= lexer
.peek_token ();
6782 while (t
->get_id () == SCOPE_RESOLUTION
)
6784 // skip scope resolution operator
6785 lexer
.skip_token ();
6787 // parse the actual segment - it is an error if it doesn't exist now
6788 std::unique_ptr
<AST::TypePathSegment
> segment
6789 = parse_type_path_segment ();
6790 if (segment
== nullptr)
6792 // skip after somewhere?
6795 "could not parse type path segment in qualified path in type");
6796 add_error (std::move (error
));
6798 return AST::QualifiedPathInType::create_error ();
6801 segments
.push_back (std::move (segment
));
6803 t
= lexer
.peek_token ();
6806 segments
.shrink_to_fit ();
6808 return AST::QualifiedPathInType (std::move (qual_path_type
),
6809 std::move (initial_segment
),
6810 std::move (segments
), locus
);
6813 // Parses a self param. Also handles self param not existing.
6814 template <typename ManagedTokenSource
>
6816 Parser
<ManagedTokenSource
>::parse_self_param ()
6818 bool has_reference
= false;
6819 AST::Lifetime lifetime
= AST::Lifetime::error ();
6821 Location locus
= lexer
.peek_token ()->get_locus ();
6823 // test if self is a reference parameter
6824 if (lexer
.peek_token ()->get_id () == AMP
)
6826 has_reference
= true;
6827 lexer
.skip_token ();
6829 // now test whether it has a lifetime
6830 if (lexer
.peek_token ()->get_id () == LIFETIME
)
6832 lifetime
= parse_lifetime ();
6834 // something went wrong somehow
6835 if (lifetime
.is_error ())
6837 Error
error (lexer
.peek_token ()->get_locus (),
6838 "failed to parse lifetime in self param");
6839 add_error (std::move (error
));
6841 // skip after somewhere?
6842 return AST::SelfParam::create_error ();
6848 bool has_mut
= false;
6849 if (lexer
.peek_token ()->get_id () == MUT
)
6852 lexer
.skip_token ();
6856 const_TokenPtr self_tok
= lexer
.peek_token ();
6857 if (self_tok
->get_id () != SELF
)
6859 // skip after somewhere?
6860 return AST::SelfParam::create_error ();
6862 lexer
.skip_token ();
6864 // parse optional type
6865 std::unique_ptr
<AST::Type
> type
= nullptr;
6866 if (lexer
.peek_token ()->get_id () == COLON
)
6868 lexer
.skip_token ();
6870 // type is now required
6871 type
= parse_type ();
6872 if (type
== nullptr)
6874 Error
error (lexer
.peek_token ()->get_locus (),
6875 "could not parse type in self param");
6876 add_error (std::move (error
));
6878 // skip after somewhere?
6879 return AST::SelfParam::create_error ();
6883 // ensure that cannot have both type and reference
6884 if (type
!= nullptr && has_reference
)
6887 lexer
.peek_token ()->get_locus (),
6888 "cannot have both a reference and a type specified in a self param");
6889 add_error (std::move (error
));
6891 // skip after somewhere?
6892 return AST::SelfParam::create_error ();
6897 return AST::SelfParam (std::move (lifetime
), has_mut
, locus
);
6901 // note that type may be nullptr here and that's fine
6902 return AST::SelfParam (std::move (type
), has_mut
, locus
);
6906 /* Parses a method. Note that this function is probably useless because using
6907 * lookahead to determine whether a function is a method is a PITA (maybe not
6908 * even doable), so most places probably parse a "function or method" and then
6909 * resolve it into whatever it is afterward. As such, this is only here for
6910 * algorithmically defining the grammar rule. */
6911 template <typename ManagedTokenSource
>
6913 Parser
<ManagedTokenSource
>::parse_method ()
6915 Location locus
= lexer
.peek_token ()->get_locus ();
6916 /* Note: as a result of the above, this will not attempt to disambiguate a
6917 * function parse qualifiers */
6918 AST::FunctionQualifiers qualifiers
= parse_function_qualifiers ();
6920 skip_token (FN_TOK
);
6922 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
6923 if (ident_tok
== nullptr)
6925 skip_after_next_block ();
6926 return AST::Method::create_error ();
6928 Identifier method_name
= ident_tok
->get_str ();
6930 // parse generic params - if exist
6931 std::vector
<std::unique_ptr
<AST::GenericParam
>> generic_params
6932 = parse_generic_params_in_angles ();
6934 if (!skip_token (LEFT_PAREN
))
6936 Error
error (lexer
.peek_token ()->get_locus (),
6937 "method missing opening parentheses before parameter list");
6938 add_error (std::move (error
));
6940 skip_after_next_block ();
6941 return AST::Method::create_error ();
6945 AST::SelfParam self_param
= parse_self_param ();
6946 if (self_param
.is_error ())
6948 Error
error (lexer
.peek_token ()->get_locus (),
6949 "could not parse self param in method");
6950 add_error (std::move (error
));
6952 skip_after_next_block ();
6953 return AST::Method::create_error ();
6956 // skip comma if it exists
6957 if (lexer
.peek_token ()->get_id () == COMMA
)
6958 lexer
.skip_token ();
6960 // parse function parameters
6961 std::vector
<AST::FunctionParam
> function_params
6962 = parse_function_params ([] (TokenId id
) { return id
== RIGHT_PAREN
; });
6964 if (!skip_token (RIGHT_PAREN
))
6966 Error
error (lexer
.peek_token ()->get_locus (),
6967 "method declaration missing closing parentheses after "
6969 add_error (std::move (error
));
6971 skip_after_next_block ();
6972 return AST::Method::create_error ();
6975 // parse function return type - if exists
6976 std::unique_ptr
<AST::Type
> return_type
= parse_function_return_type ();
6978 // parse where clause - if exists
6979 AST::WhereClause where_clause
= parse_where_clause ();
6981 // parse block expression
6982 std::unique_ptr
<AST::BlockExpr
> block_expr
= parse_block_expr ();
6983 if (block_expr
== nullptr)
6985 Error
error (lexer
.peek_token ()->get_locus (),
6986 "method declaration missing block expression");
6987 add_error (std::move (error
));
6989 skip_after_end_block ();
6990 return AST::Method::create_error ();
6993 // does not parse visibility, but this method isn't used, so doesn't matter
6994 return AST::Method (std::move (method_name
), std::move (qualifiers
),
6995 std::move (generic_params
), std::move (self_param
),
6996 std::move (function_params
), std::move (return_type
),
6997 std::move (where_clause
), std::move (block_expr
),
6998 AST::Visibility::create_error (), AST::AttrVec (), locus
);
7001 /* Parses an expression statement (disambiguates to expression with or without
7002 * block statement). */
7003 template <typename ManagedTokenSource
>
7004 std::unique_ptr
<AST::ExprStmt
>
7005 Parser
<ManagedTokenSource
>::parse_expr_stmt (AST::AttrVec outer_attrs
,
7006 ParseRestrictions restrictions
)
7008 /* potential thoughts - define new virtual method "has_block()" on expr.
7009 * parse expr and then determine whether semicolon is needed as a result of
7010 * this method. but then this would require dynamic_cast, which is not
7013 /* okay new thought - big switch to disambiguate exprs with blocks - either
7014 * block expr, async block expr, unsafe block expr, loop expr, if expr, if
7015 * let expr, or match expr. So all others are exprs without block. */
7016 /* new thought: possible initial tokens: 'loop', 'while', 'for', lifetime
7017 * (and then ':' and then loop), 'if', 'match', '{', 'async', 'unsafe' (and
7019 * '{')). This seems to have no ambiguity. */
7021 const_TokenPtr t
= lexer
.peek_token ();
7022 /* TODO: should the switch just directly call the individual parse methods
7023 * rather than adding another layer of indirection with
7024 * parse_expr_stmt_with_block()? */
7025 switch (t
->get_id ())
7034 // expression with block
7035 return parse_expr_stmt_with_block (std::move (outer_attrs
));
7037 /* FIXME: are there any expressions without blocks that can have
7038 * lifetime as their first token? Or is loop expr the only one? */
7039 // safe side for now:
7040 if (lexer
.peek_token (1)->get_id () == COLON
7041 && lexer
.peek_token (2)->get_id () == LOOP
)
7043 return parse_expr_stmt_with_block (std::move (outer_attrs
));
7047 return parse_expr_stmt_without_block (std::move (outer_attrs
),
7052 /* FIXME: are there any expressions without blocks that can have
7053 * unsafe as their first token? Or is unsafe the only one? */
7054 // safe side for now
7055 if (lexer
.peek_token (1)->get_id () == LEFT_CURLY
)
7057 return parse_expr_stmt_with_block (std::move (outer_attrs
));
7061 return parse_expr_stmt_without_block (std::move (outer_attrs
),
7066 // not a parse expr with block, so must be expr without block
7067 /* TODO: if possible, be more selective about possible expr without
7068 * block initial tokens in order to prevent more syntactical errors at
7070 return parse_expr_stmt_without_block (std::move (outer_attrs
),
7075 template <typename ManagedTokenSource
>
7076 std::unique_ptr
<AST::ExprWithBlock
>
7077 Parser
<ManagedTokenSource
>::parse_expr_with_block (AST::AttrVec outer_attrs
)
7079 std::unique_ptr
<AST::ExprWithBlock
> expr_parsed
= nullptr;
7081 const_TokenPtr t
= lexer
.peek_token ();
7082 switch (t
->get_id ())
7085 // if or if let, so more lookahead to find out
7086 if (lexer
.peek_token (1)->get_id () == LET
)
7089 expr_parsed
= parse_if_let_expr (std::move (outer_attrs
));
7095 expr_parsed
= parse_if_expr (std::move (outer_attrs
));
7100 expr_parsed
= parse_loop_expr (std::move (outer_attrs
));
7103 // "for" iterator loop
7104 expr_parsed
= parse_for_loop_expr (std::move (outer_attrs
));
7107 // while or while let, so more lookahead to find out
7108 if (lexer
.peek_token (1)->get_id () == LET
)
7110 // while let loop expr
7111 expr_parsed
= parse_while_let_loop_expr (std::move (outer_attrs
));
7117 expr_parsed
= parse_while_loop_expr (std::move (outer_attrs
));
7123 expr_parsed
= parse_match_expr (std::move (outer_attrs
));
7127 expr_parsed
= parse_block_expr (std::move (outer_attrs
));
7130 // async block expression
7131 expr_parsed
= parse_async_block_expr (std::move (outer_attrs
));
7134 // unsafe block expression
7135 expr_parsed
= parse_unsafe_block_expr (std::move (outer_attrs
));
7138 // some kind of loop expr (with loop label)
7139 expr_parsed
= parse_labelled_loop_expr (std::move (outer_attrs
));
7144 "could not recognise expr beginning with %qs as an expr with block in"
7145 " parsing expr statement",
7146 t
->get_token_description ()));
7148 skip_after_next_block ();
7152 // ensure expr parsed exists
7153 if (expr_parsed
== nullptr)
7155 Error
error (t
->get_locus (),
7156 "failed to parse expr with block in parsing expr statement");
7157 add_error (std::move (error
));
7159 skip_after_end_block ();
7166 /* Parses a expression statement containing an expression with block.
7167 * Disambiguates internally. */
7168 template <typename ManagedTokenSource
>
7169 std::unique_ptr
<AST::ExprStmtWithBlock
>
7170 Parser
<ManagedTokenSource
>::parse_expr_stmt_with_block (
7171 AST::AttrVec outer_attrs
)
7173 auto expr_parsed
= parse_expr_with_block (std::move (outer_attrs
));
7174 auto locus
= expr_parsed
->get_locus ();
7176 // return expr stmt created from expr
7177 return std::unique_ptr
<AST::ExprStmtWithBlock
> (
7178 new AST::ExprStmtWithBlock (std::move (expr_parsed
), locus
,
7179 lexer
.peek_token ()->get_id () == SEMICOLON
));
7182 /* Parses an expression statement containing an expression without block.
7183 * Disambiguates further. */
7184 template <typename ManagedTokenSource
>
7185 std::unique_ptr
<AST::ExprStmtWithoutBlock
>
7186 Parser
<ManagedTokenSource
>::parse_expr_stmt_without_block (
7187 AST::AttrVec outer_attrs
, ParseRestrictions restrictions
)
7189 /* TODO: maybe move more logic for expr without block in here for better
7192 // attempt to parse via parse_expr_without_block - seems to work
7193 std::unique_ptr
<AST::ExprWithoutBlock
> expr
= nullptr;
7194 Location locus
= lexer
.peek_token ()->get_locus ();
7196 restrictions
.expr_can_be_stmt
= true;
7198 expr
= parse_expr_without_block (std::move (outer_attrs
), restrictions
);
7199 if (expr
== nullptr)
7201 // expr is required, error
7202 Error
error (lexer
.peek_token ()->get_locus (),
7203 "failed to parse expr without block in expr statement");
7204 add_error (std::move (error
));
7206 skip_after_semicolon ();
7210 if (restrictions
.consume_semi
)
7211 if (!skip_token (SEMICOLON
))
7214 return std::unique_ptr
<AST::ExprStmtWithoutBlock
> (
7215 new AST::ExprStmtWithoutBlock (std::move (expr
), locus
));
7218 /* Parses an expression without a block associated with it (further
7219 * disambiguates). */
7220 template <typename ManagedTokenSource
>
7221 std::unique_ptr
<AST::ExprWithoutBlock
>
7222 Parser
<ManagedTokenSource
>::parse_expr_without_block (
7223 AST::AttrVec outer_attrs
, ParseRestrictions restrictions
)
7225 /* Notes on types of expr without block:
7226 * - literal expr tokens that are literals
7227 * - path expr path_in_expr or qual_path_in_expr
7228 * - operator expr many different types
7230 * borrow expr ( '&' | '&&' ) 'mut'? expr
7231 * dereference expr '*' expr
7232 * error propagation expr '?'
7235 * binary: all start with expr
7236 * - grouped/paren expr '(' inner_attributes expr ')'
7237 * - array expr '[' inner_attributes array_elems? ']'
7238 * - await expr expr '.' 'await'
7239 * - (array/slice) index expr expr '[' expr ']'
7240 * - tuple expr '(' inner_attributes tuple_elems? ')'
7241 * note that a single elem tuple is distinguished from a grouped expr
7242 * by a trailing comma, i.e. a grouped expr is preferred over a tuple expr
7243 * - tuple index expr expr '.' tuple_index
7244 * - struct expr path_in_expr (and optional other stuff)
7245 * - enum variant expr path_in_expr (and optional other stuff)
7246 * this means that there is no syntactic difference between an enum
7247 * variant and a struct
7248 * - only name resolution can tell the difference. Thus, maybe rework
7249 * AST to take this into account ("struct or enum" nodes?)
7250 * - (function) call expr expr '(' call_params? ')'
7251 * - method call expr expr '.' path_expr_segment '(' call_params? ')'
7252 * - field expr expr '.' identifier
7253 * note that method call expr is preferred, i.e. field expr must not be
7254 * followed by parenthesised expression sequence.
7255 * - closure expr 'move'? ( '||' | '|' closure_params? '|' ) (
7256 * expr | '->' type_no_bounds block_expr )
7257 * - continue expr 'continue' labelled_lifetime?
7258 * - break expr 'break' labelled_lifetime? expr?
7259 * - range expr many different types but all involve '..' or
7261 * - return expr 'return' as 1st tok
7262 * - macro invocation identifier then :: or identifier then !
7265 * any that have rules beginning with 'expr' should probably be
7267 * with parsing type to use determined by token AND lookahead. */
7269 // ok well at least can do easy ones
7270 const_TokenPtr t
= lexer
.peek_token ();
7271 switch (t
->get_id ())
7275 return parse_return_expr (std::move (outer_attrs
));
7278 return parse_break_expr (std::move (outer_attrs
));
7281 return parse_continue_expr (std::move (outer_attrs
));
7283 // closure expr (though not all closure exprs require this)
7284 return parse_closure_expr (std::move (outer_attrs
));
7286 // array expr (creation, not index)
7287 return parse_array_expr (std::move (outer_attrs
));
7289 /* HACK: piggyback on pratt parsed expr and abuse polymorphism to
7290 * essentially downcast */
7292 std::unique_ptr
<AST::Expr
> expr
7293 = parse_expr (std::move (outer_attrs
), restrictions
);
7295 if (expr
== nullptr)
7297 Error
error (t
->get_locus (),
7298 "failed to parse expression for expression without "
7299 "block (pratt-parsed expression is null)");
7300 add_error (std::move (error
));
7305 std::unique_ptr
<AST::ExprWithoutBlock
> expr_without_block (
7306 expr
->as_expr_without_block ());
7308 if (expr_without_block
!= nullptr)
7310 return expr_without_block
;
7314 Error
error (t
->get_locus (),
7315 "converted expr without block is null");
7316 add_error (std::move (error
));
7324 // Parses a block expression, including the curly braces at start and end.
7325 template <typename ManagedTokenSource
>
7326 std::unique_ptr
<AST::BlockExpr
>
7327 Parser
<ManagedTokenSource
>::parse_block_expr (AST::AttrVec outer_attrs
,
7328 Location pratt_parsed_loc
)
7330 Location locus
= pratt_parsed_loc
;
7331 if (locus
== Linemap::unknown_location ())
7333 locus
= lexer
.peek_token ()->get_locus ();
7334 if (!skip_token (LEFT_CURLY
))
7336 skip_after_end_block ();
7341 AST::AttrVec inner_attrs
= parse_inner_attributes ();
7343 // parse statements and expression
7344 std::vector
<std::unique_ptr
<AST::Stmt
>> stmts
;
7345 std::unique_ptr
<AST::Expr
> expr
= nullptr;
7347 const_TokenPtr t
= lexer
.peek_token ();
7348 while (t
->get_id () != RIGHT_CURLY
)
7350 ExprOrStmt expr_or_stmt
= parse_stmt_or_expr_without_block ();
7351 if (expr_or_stmt
.is_error ())
7353 Error
error (t
->get_locus (),
7354 "failed to parse statement or expression without "
7355 "block in block expression");
7356 add_error (std::move (error
));
7361 t
= lexer
.peek_token ();
7363 if (expr_or_stmt
.stmt
!= nullptr)
7365 stmts
.push_back (std::move (expr_or_stmt
.stmt
));
7369 // assign to expression and end parsing inside
7370 expr
= std::move (expr_or_stmt
.expr
);
7375 Location end_locus
= t
->get_locus ();
7377 if (!skip_token (RIGHT_CURLY
))
7379 Error
error (t
->get_locus (),
7380 "error may be from having an expression (as opposed to "
7381 "statement) in the body of the function but not last");
7382 add_error (std::move (error
));
7384 skip_after_end_block ();
7388 // grammar allows for empty block expressions
7390 stmts
.shrink_to_fit ();
7392 return std::unique_ptr
<AST::BlockExpr
> (
7393 new AST::BlockExpr (std::move (stmts
), std::move (expr
),
7394 std::move (inner_attrs
), std::move (outer_attrs
), locus
,
7398 /* Parses a "grouped" expression (expression in parentheses), used to control
7400 template <typename ManagedTokenSource
>
7401 std::unique_ptr
<AST::GroupedExpr
>
7402 Parser
<ManagedTokenSource
>::parse_grouped_expr (AST::AttrVec outer_attrs
)
7404 Location locus
= lexer
.peek_token ()->get_locus ();
7405 skip_token (LEFT_PAREN
);
7407 AST::AttrVec inner_attrs
= parse_inner_attributes ();
7409 // parse required expr inside parentheses
7410 std::unique_ptr
<AST::Expr
> expr_in_parens
= parse_expr ();
7411 if (expr_in_parens
== nullptr)
7413 // skip after somewhere?
7418 if (!skip_token (RIGHT_PAREN
))
7420 // skip after somewhere?
7424 return std::unique_ptr
<AST::GroupedExpr
> (
7425 new AST::GroupedExpr (std::move (expr_in_parens
), std::move (inner_attrs
),
7426 std::move (outer_attrs
), locus
));
7429 // Parses a closure expression (closure definition).
7430 template <typename ManagedTokenSource
>
7431 std::unique_ptr
<AST::ClosureExpr
>
7432 Parser
<ManagedTokenSource
>::parse_closure_expr (AST::AttrVec outer_attrs
)
7434 Location locus
= lexer
.peek_token ()->get_locus ();
7435 // detect optional "move"
7436 bool has_move
= false;
7437 if (lexer
.peek_token ()->get_id () == MOVE
)
7439 lexer
.skip_token ();
7443 // handle parameter list
7444 std::vector
<AST::ClosureParam
> params
;
7446 const_TokenPtr t
= lexer
.peek_token ();
7447 switch (t
->get_id ())
7450 // skip token, no parameters
7451 lexer
.skip_token ();
7454 // actually may have parameters
7455 lexer
.skip_token ();
7457 while (t
->get_id () != PIPE
)
7459 AST::ClosureParam param
= parse_closure_param ();
7460 if (param
.is_error ())
7462 // TODO is this really an error?
7463 Error
error (t
->get_locus (), "could not parse closure param");
7464 add_error (std::move (error
));
7468 params
.push_back (std::move (param
));
7470 if (lexer
.peek_token ()->get_id () != COMMA
)
7472 // not an error but means param list is done
7476 lexer
.skip_token ();
7478 t
= lexer
.peek_token ();
7480 params
.shrink_to_fit ();
7483 add_error (Error (t
->get_locus (),
7484 "unexpected token %qs in closure expression - expected "
7486 t
->get_token_description ()));
7492 // again branch based on next token
7493 t
= lexer
.peek_token ();
7494 if (t
->get_id () == RETURN_TYPE
)
7496 // must be return type closure with block expr
7498 // skip "return type" token
7499 lexer
.skip_token ();
7501 // parse actual type, which is required
7502 std::unique_ptr
<AST::TypeNoBounds
> type
= parse_type_no_bounds ();
7503 if (type
== nullptr)
7506 Error
error (t
->get_locus (), "failed to parse type for closure");
7507 add_error (std::move (error
));
7513 // parse block expr, which is required
7514 std::unique_ptr
<AST::BlockExpr
> block
= parse_block_expr ();
7515 if (block
== nullptr)
7518 Error
error (lexer
.peek_token ()->get_locus (),
7519 "failed to parse block expr in closure");
7520 add_error (std::move (error
));
7526 return std::unique_ptr
<AST::ClosureExprInnerTyped
> (
7527 new AST::ClosureExprInnerTyped (std::move (type
), std::move (block
),
7528 std::move (params
), locus
, has_move
,
7529 std::move (outer_attrs
)));
7533 // must be expr-only closure
7535 // parse expr, which is required
7536 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
7537 if (expr
== nullptr)
7539 Error
error (t
->get_locus (),
7540 "failed to parse expression in closure");
7541 add_error (std::move (error
));
7547 return std::unique_ptr
<AST::ClosureExprInner
> (
7548 new AST::ClosureExprInner (std::move (expr
), std::move (params
), locus
,
7549 has_move
, std::move (outer_attrs
)));
7553 // Parses a literal token (to literal expression).
7554 template <typename ManagedTokenSource
>
7555 std::unique_ptr
<AST::LiteralExpr
>
7556 Parser
<ManagedTokenSource
>::parse_literal_expr (AST::AttrVec outer_attrs
)
7558 // TODO: change if literal representation in lexer changes
7560 std::string literal_value
;
7561 AST::Literal::LitType type
= AST::Literal::STRING
;
7563 // branch based on token
7564 const_TokenPtr t
= lexer
.peek_token ();
7565 switch (t
->get_id ())
7568 type
= AST::Literal::CHAR
;
7569 literal_value
= t
->get_str ();
7570 lexer
.skip_token ();
7572 case STRING_LITERAL
:
7573 type
= AST::Literal::STRING
;
7574 literal_value
= t
->get_str ();
7575 lexer
.skip_token ();
7577 case BYTE_CHAR_LITERAL
:
7578 type
= AST::Literal::BYTE
;
7579 literal_value
= t
->get_str ();
7580 lexer
.skip_token ();
7582 case BYTE_STRING_LITERAL
:
7583 type
= AST::Literal::BYTE_STRING
;
7584 literal_value
= t
->get_str ();
7585 lexer
.skip_token ();
7588 type
= AST::Literal::INT
;
7589 literal_value
= t
->get_str ();
7590 lexer
.skip_token ();
7593 type
= AST::Literal::FLOAT
;
7594 literal_value
= t
->get_str ();
7595 lexer
.skip_token ();
7597 // case BOOL_LITERAL
7598 // use true and false keywords rather than "bool literal" Rust terminology
7600 type
= AST::Literal::BOOL
;
7601 literal_value
= "true";
7602 lexer
.skip_token ();
7605 type
= AST::Literal::BOOL
;
7606 literal_value
= "false";
7607 lexer
.skip_token ();
7610 // error - cannot be a literal expr
7611 add_error (Error (t
->get_locus (),
7612 "unexpected token %qs when parsing literal expression",
7613 t
->get_token_description ()));
7619 // create literal based on stuff in switch
7620 return std::unique_ptr
<AST::LiteralExpr
> (
7621 new AST::LiteralExpr (std::move (literal_value
), std::move (type
),
7622 t
->get_type_hint (), std::move (outer_attrs
),
7626 // Parses a return expression (including any expression to return).
7627 template <typename ManagedTokenSource
>
7628 std::unique_ptr
<AST::ReturnExpr
>
7629 Parser
<ManagedTokenSource
>::parse_return_expr (AST::AttrVec outer_attrs
,
7630 Location pratt_parsed_loc
)
7632 Location locus
= pratt_parsed_loc
;
7633 if (locus
== Linemap::unknown_location ())
7635 locus
= lexer
.peek_token ()->get_locus ();
7636 skip_token (RETURN_TOK
);
7639 // parse expression to return, if it exists
7640 ParseRestrictions restrictions
;
7641 restrictions
.expr_can_be_null
= true;
7642 std::unique_ptr
<AST::Expr
> returned_expr
7643 = parse_expr (AST::AttrVec (), restrictions
);
7645 return std::unique_ptr
<AST::ReturnExpr
> (
7646 new AST::ReturnExpr (std::move (returned_expr
), std::move (outer_attrs
),
7650 /* Parses a break expression (including any label to break to AND any return
7652 template <typename ManagedTokenSource
>
7653 std::unique_ptr
<AST::BreakExpr
>
7654 Parser
<ManagedTokenSource
>::parse_break_expr (AST::AttrVec outer_attrs
,
7655 Location pratt_parsed_loc
)
7657 Location locus
= pratt_parsed_loc
;
7658 if (locus
== Linemap::unknown_location ())
7660 locus
= lexer
.peek_token ()->get_locus ();
7664 // parse label (lifetime) if it exists - create dummy first
7665 AST::Lifetime label
= AST::Lifetime::error ();
7666 if (lexer
.peek_token ()->get_id () == LIFETIME
)
7668 label
= parse_lifetime ();
7671 // parse break return expression if it exists
7672 ParseRestrictions restrictions
;
7673 restrictions
.expr_can_be_null
= true;
7674 std::unique_ptr
<AST::Expr
> return_expr
7675 = parse_expr (AST::AttrVec (), restrictions
);
7677 return std::unique_ptr
<AST::BreakExpr
> (
7678 new AST::BreakExpr (std::move (label
), std::move (return_expr
),
7679 std::move (outer_attrs
), locus
));
7682 // Parses a continue expression (including any label to continue from).
7683 template <typename ManagedTokenSource
>
7684 std::unique_ptr
<AST::ContinueExpr
>
7685 Parser
<ManagedTokenSource
>::parse_continue_expr (AST::AttrVec outer_attrs
,
7686 Location pratt_parsed_loc
)
7688 Location locus
= pratt_parsed_loc
;
7689 if (locus
== Linemap::unknown_location ())
7691 locus
= lexer
.peek_token ()->get_locus ();
7692 skip_token (CONTINUE
);
7695 // parse label (lifetime) if it exists - create dummy first
7696 AST::Lifetime label
= AST::Lifetime::error ();
7697 if (lexer
.peek_token ()->get_id () == LIFETIME
)
7699 label
= parse_lifetime ();
7702 return std::unique_ptr
<AST::ContinueExpr
> (
7703 new AST::ContinueExpr (std::move (label
), std::move (outer_attrs
), locus
));
7706 // Parses a loop label used in loop expressions.
7707 template <typename ManagedTokenSource
>
7709 Parser
<ManagedTokenSource
>::parse_loop_label ()
7711 // parse lifetime - if doesn't exist, assume no label
7712 const_TokenPtr t
= lexer
.peek_token ();
7713 if (t
->get_id () != LIFETIME
)
7715 // not necessarily an error
7716 return AST::LoopLabel::error ();
7718 /* FIXME: check for named lifetime requirement here? or check in semantic
7719 * analysis phase? */
7720 AST::Lifetime label
= parse_lifetime ();
7722 if (!skip_token (COLON
))
7725 return AST::LoopLabel::error ();
7728 return AST::LoopLabel (std::move (label
), t
->get_locus ());
7731 /* Parses an if expression of any kind, including with else, else if, else if
7732 * let, and neither. Note that any outer attributes will be ignored because if
7733 * expressions don't support them. */
7734 template <typename ManagedTokenSource
>
7735 std::unique_ptr
<AST::IfExpr
>
7736 Parser
<ManagedTokenSource
>::parse_if_expr (AST::AttrVec outer_attrs
,
7737 Location pratt_parsed_loc
)
7739 // TODO: make having outer attributes an error?
7740 Location locus
= pratt_parsed_loc
;
7741 if (locus
== Linemap::unknown_location ())
7743 locus
= lexer
.peek_token ()->get_locus ();
7744 if (!skip_token (IF
))
7746 skip_after_end_block ();
7751 // detect accidental if let
7752 if (lexer
.peek_token ()->get_id () == LET
)
7754 Error
error (lexer
.peek_token ()->get_locus (),
7755 "if let expression probably exists, but is being parsed "
7756 "as an if expression. This may be a parser error");
7757 add_error (std::move (error
));
7763 /* parse required condition expr - HACK to prevent struct expr from being
7765 ParseRestrictions no_struct_expr
;
7766 no_struct_expr
.can_be_struct_expr
= false;
7767 std::unique_ptr
<AST::Expr
> condition
= parse_expr ({}, no_struct_expr
);
7768 if (condition
== nullptr)
7770 Error
error (lexer
.peek_token ()->get_locus (),
7771 "failed to parse condition expression in if expression");
7772 add_error (std::move (error
));
7778 // parse required block expr
7779 std::unique_ptr
<AST::BlockExpr
> if_body
= parse_block_expr ();
7780 if (if_body
== nullptr)
7782 Error
error (lexer
.peek_token ()->get_locus (),
7783 "failed to parse if body block expression in if expression");
7784 add_error (std::move (error
));
7790 // branch to parse end or else (and then else, else if, or else if let)
7791 if (lexer
.peek_token ()->get_id () != ELSE
)
7793 // single selection - end of if expression
7794 return std::unique_ptr
<AST::IfExpr
> (
7795 new AST::IfExpr (std::move (condition
), std::move (if_body
),
7796 std::move (outer_attrs
), locus
));
7800 // double or multiple selection - branch on end, else if, or else if let
7803 lexer
.skip_token ();
7805 // branch on whether next token is '{' or 'if'
7806 const_TokenPtr t
= lexer
.peek_token ();
7807 switch (t
->get_id ())
7810 // double selection - else
7811 // parse else block expr (required)
7812 std::unique_ptr
<AST::BlockExpr
> else_body
= parse_block_expr ();
7813 if (else_body
== nullptr)
7815 Error
error (lexer
.peek_token ()->get_locus (),
7816 "failed to parse else body block expression in "
7818 add_error (std::move (error
));
7824 return std::unique_ptr
<AST::IfExprConseqElse
> (
7825 new AST::IfExprConseqElse (std::move (condition
),
7826 std::move (if_body
),
7827 std::move (else_body
),
7828 std::move (outer_attrs
), locus
));
7831 // multiple selection - else if or else if let
7832 // branch on whether next token is 'let' or not
7833 if (lexer
.peek_token (1)->get_id () == LET
)
7835 // parse if let expr (required)
7836 std::unique_ptr
<AST::IfLetExpr
> if_let_expr
7837 = parse_if_let_expr ();
7838 if (if_let_expr
== nullptr)
7840 Error
error (lexer
.peek_token ()->get_locus (),
7841 "failed to parse (else) if let expression "
7842 "after if expression");
7843 add_error (std::move (error
));
7849 return std::unique_ptr
<AST::IfExprConseqIfLet
> (
7850 new AST::IfExprConseqIfLet (std::move (condition
),
7851 std::move (if_body
),
7852 std::move (if_let_expr
),
7853 std::move (outer_attrs
), locus
));
7857 // parse if expr (required)
7858 std::unique_ptr
<AST::IfExpr
> if_expr
= parse_if_expr ();
7859 if (if_expr
== nullptr)
7861 Error
error (lexer
.peek_token ()->get_locus (),
7862 "failed to parse (else) if expression after "
7864 add_error (std::move (error
));
7870 return std::unique_ptr
<AST::IfExprConseqIf
> (
7871 new AST::IfExprConseqIf (std::move (condition
),
7872 std::move (if_body
),
7873 std::move (if_expr
),
7874 std::move (outer_attrs
), locus
));
7878 // error - invalid token
7879 add_error (Error (t
->get_locus (),
7880 "unexpected token %qs after else in if expression",
7881 t
->get_token_description ()));
7889 /* Parses an if let expression of any kind, including with else, else if, else
7890 * if let, and none. Note that any outer attributes will be ignored as if let
7891 * expressions don't support them. */
7892 template <typename ManagedTokenSource
>
7893 std::unique_ptr
<AST::IfLetExpr
>
7894 Parser
<ManagedTokenSource
>::parse_if_let_expr (AST::AttrVec outer_attrs
,
7895 Location pratt_parsed_loc
)
7897 // TODO: make having outer attributes an error?
7898 Location locus
= pratt_parsed_loc
;
7899 if (locus
== Linemap::unknown_location ())
7901 locus
= lexer
.peek_token ()->get_locus ();
7902 if (!skip_token (IF
))
7904 skip_after_end_block ();
7909 // detect accidental if expr parsed as if let expr
7910 if (lexer
.peek_token ()->get_id () != LET
)
7912 Error
error (lexer
.peek_token ()->get_locus (),
7913 "if expression probably exists, but is being parsed as an "
7914 "if let expression. This may be a parser error");
7915 add_error (std::move (error
));
7920 lexer
.skip_token ();
7922 // parse match arm patterns (which are required)
7923 std::vector
<std::unique_ptr
<AST::Pattern
>> match_arm_patterns
7924 = parse_match_arm_patterns (EQUAL
);
7925 if (match_arm_patterns
.empty ())
7928 lexer
.peek_token ()->get_locus (),
7929 "failed to parse any match arm patterns in if let expression");
7930 add_error (std::move (error
));
7936 if (!skip_token (EQUAL
))
7942 // parse expression (required) - HACK to prevent struct expr being parsed
7943 ParseRestrictions no_struct_expr
;
7944 no_struct_expr
.can_be_struct_expr
= false;
7945 std::unique_ptr
<AST::Expr
> scrutinee_expr
= parse_expr ({}, no_struct_expr
);
7946 if (scrutinee_expr
== nullptr)
7948 Error
error (lexer
.peek_token ()->get_locus (),
7949 "failed to parse scrutinee expression in if let expression");
7950 add_error (std::move (error
));
7955 /* TODO: check for expression not being a struct expression or lazy boolean
7956 * expression here? or actually probably in semantic analysis. */
7958 // parse block expression (required)
7959 std::unique_ptr
<AST::BlockExpr
> if_let_body
= parse_block_expr ();
7960 if (if_let_body
== nullptr)
7963 lexer
.peek_token ()->get_locus (),
7964 "failed to parse if let body block expression in if let expression");
7965 add_error (std::move (error
));
7971 // branch to parse end or else (and then else, else if, or else if let)
7972 if (lexer
.peek_token ()->get_id () != ELSE
)
7974 // single selection - end of if let expression
7975 return std::unique_ptr
<AST::IfLetExpr
> (
7976 new AST::IfLetExpr (std::move (match_arm_patterns
),
7977 std::move (scrutinee_expr
), std::move (if_let_body
),
7978 std::move (outer_attrs
), locus
));
7982 // double or multiple selection - branch on end, else if, or else if let
7985 lexer
.skip_token ();
7987 // branch on whether next token is '{' or 'if'
7988 const_TokenPtr t
= lexer
.peek_token ();
7989 switch (t
->get_id ())
7992 // double selection - else
7993 // parse else block expr (required)
7994 std::unique_ptr
<AST::BlockExpr
> else_body
= parse_block_expr ();
7995 if (else_body
== nullptr)
7997 Error
error (lexer
.peek_token ()->get_locus (),
7998 "failed to parse else body block expression in "
7999 "if let expression");
8000 add_error (std::move (error
));
8006 return std::unique_ptr
<AST::IfLetExprConseqElse
> (
8007 new AST::IfLetExprConseqElse (std::move (match_arm_patterns
),
8008 std::move (scrutinee_expr
),
8009 std::move (if_let_body
),
8010 std::move (else_body
),
8011 std::move (outer_attrs
), locus
));
8014 // multiple selection - else if or else if let
8015 // branch on whether next token is 'let' or not
8016 if (lexer
.peek_token (1)->get_id () == LET
)
8018 // parse if let expr (required)
8019 std::unique_ptr
<AST::IfLetExpr
> if_let_expr
8020 = parse_if_let_expr ();
8021 if (if_let_expr
== nullptr)
8023 Error
error (lexer
.peek_token ()->get_locus (),
8024 "failed to parse (else) if let expression "
8025 "after if let expression");
8026 add_error (std::move (error
));
8032 return std::unique_ptr
<AST::IfLetExprConseqIfLet
> (
8033 new AST::IfLetExprConseqIfLet (
8034 std::move (match_arm_patterns
), std::move (scrutinee_expr
),
8035 std::move (if_let_body
), std::move (if_let_expr
),
8036 std::move (outer_attrs
), locus
));
8040 // parse if expr (required)
8041 std::unique_ptr
<AST::IfExpr
> if_expr
= parse_if_expr ();
8042 if (if_expr
== nullptr)
8044 Error
error (lexer
.peek_token ()->get_locus (),
8045 "failed to parse (else) if expression after "
8046 "if let expression");
8047 add_error (std::move (error
));
8053 return std::unique_ptr
<AST::IfLetExprConseqIf
> (
8054 new AST::IfLetExprConseqIf (std::move (match_arm_patterns
),
8055 std::move (scrutinee_expr
),
8056 std::move (if_let_body
),
8057 std::move (if_expr
),
8058 std::move (outer_attrs
), locus
));
8062 // error - invalid token
8064 Error (t
->get_locus (),
8065 "unexpected token %qs after else in if let expression",
8066 t
->get_token_description ()));
8074 /* TODO: possibly decide on different method of handling label (i.e. not
8077 /* Parses a "loop" infinite loop expression. Label is not parsed and should be
8078 * parsed via parse_labelled_loop_expr, which would call this. */
8079 template <typename ManagedTokenSource
>
8080 std::unique_ptr
<AST::LoopExpr
>
8081 Parser
<ManagedTokenSource
>::parse_loop_expr (AST::AttrVec outer_attrs
,
8082 AST::LoopLabel label
,
8083 Location pratt_parsed_loc
)
8085 Location locus
= pratt_parsed_loc
;
8086 if (locus
== Linemap::unknown_location ())
8088 if (label
.is_error ())
8089 locus
= lexer
.peek_token ()->get_locus ();
8091 locus
= label
.get_locus ();
8093 if (!skip_token (LOOP
))
8095 skip_after_end_block ();
8101 if (!label
.is_error ())
8102 locus
= label
.get_locus ();
8105 // parse loop body, which is required
8106 std::unique_ptr
<AST::BlockExpr
> loop_body
= parse_block_expr ();
8107 if (loop_body
== nullptr)
8109 Error
error (lexer
.peek_token ()->get_locus (),
8110 "could not parse loop body in (infinite) loop expression");
8111 add_error (std::move (error
));
8116 return std::unique_ptr
<AST::LoopExpr
> (
8117 new AST::LoopExpr (std::move (loop_body
), locus
, std::move (label
),
8118 std::move (outer_attrs
)));
8121 /* Parses a "while" loop expression. Label is not parsed and should be parsed
8122 * via parse_labelled_loop_expr, which would call this. */
8123 template <typename ManagedTokenSource
>
8124 std::unique_ptr
<AST::WhileLoopExpr
>
8125 Parser
<ManagedTokenSource
>::parse_while_loop_expr (AST::AttrVec outer_attrs
,
8126 AST::LoopLabel label
,
8127 Location pratt_parsed_loc
)
8129 Location locus
= pratt_parsed_loc
;
8130 if (locus
== Linemap::unknown_location ())
8132 if (label
.is_error ())
8133 locus
= lexer
.peek_token ()->get_locus ();
8135 locus
= label
.get_locus ();
8137 if (!skip_token (WHILE
))
8139 skip_after_end_block ();
8145 if (!label
.is_error ())
8146 locus
= label
.get_locus ();
8149 // ensure it isn't a while let loop
8150 if (lexer
.peek_token ()->get_id () == LET
)
8152 Error
error (lexer
.peek_token ()->get_locus (),
8153 "appears to be while let loop but is being parsed by "
8154 "while loop - this may be a compiler issue");
8155 add_error (std::move (error
));
8161 // parse loop predicate (required) with HACK to prevent struct expr parsing
8162 ParseRestrictions no_struct_expr
;
8163 no_struct_expr
.can_be_struct_expr
= false;
8164 std::unique_ptr
<AST::Expr
> predicate
= parse_expr ({}, no_struct_expr
);
8165 if (predicate
== nullptr)
8167 Error
error (lexer
.peek_token ()->get_locus (),
8168 "failed to parse predicate expression in while loop");
8169 add_error (std::move (error
));
8174 /* TODO: check that it isn't struct expression here? actually, probably in
8175 * semantic analysis */
8177 // parse loop body (required)
8178 std::unique_ptr
<AST::BlockExpr
> body
= parse_block_expr ();
8179 if (body
== nullptr)
8181 Error
error (lexer
.peek_token ()->get_locus (),
8182 "failed to parse loop body block expression in while loop");
8183 add_error (std::move (error
));
8189 return std::unique_ptr
<AST::WhileLoopExpr
> (
8190 new AST::WhileLoopExpr (std::move (predicate
), std::move (body
), locus
,
8191 std::move (label
), std::move (outer_attrs
)));
8194 /* Parses a "while let" loop expression. Label is not parsed and should be
8195 * parsed via parse_labelled_loop_expr, which would call this. */
8196 template <typename ManagedTokenSource
>
8197 std::unique_ptr
<AST::WhileLetLoopExpr
>
8198 Parser
<ManagedTokenSource
>::parse_while_let_loop_expr (AST::AttrVec outer_attrs
,
8199 AST::LoopLabel label
)
8201 Location locus
= Linemap::unknown_location ();
8202 if (label
.is_error ())
8203 locus
= lexer
.peek_token ()->get_locus ();
8205 locus
= label
.get_locus ();
8208 /* check for possible accidental recognition of a while loop as a while let
8210 if (lexer
.peek_token ()->get_id () != LET
)
8212 Error
error (lexer
.peek_token ()->get_locus (),
8213 "appears to be a while loop but is being parsed by "
8214 "while let loop - this may be a compiler issue");
8215 add_error (std::move (error
));
8220 // as this token is definitely let now, save the computation of comparison
8221 lexer
.skip_token ();
8223 // parse predicate patterns
8224 std::vector
<std::unique_ptr
<AST::Pattern
>> predicate_patterns
8225 = parse_match_arm_patterns (EQUAL
);
8226 // TODO: have to ensure that there is at least 1 pattern?
8228 if (!skip_token (EQUAL
))
8234 /* parse predicate expression, which is required (and HACK to prevent struct
8236 ParseRestrictions no_struct_expr
;
8237 no_struct_expr
.can_be_struct_expr
= false;
8238 std::unique_ptr
<AST::Expr
> predicate_expr
= parse_expr ({}, no_struct_expr
);
8239 if (predicate_expr
== nullptr)
8241 Error
error (lexer
.peek_token ()->get_locus (),
8242 "failed to parse predicate expression in while let loop");
8243 add_error (std::move (error
));
8248 /* TODO: ensure that struct expression is not parsed? Actually, probably in
8249 * semantic analysis. */
8251 // parse loop body, which is required
8252 std::unique_ptr
<AST::BlockExpr
> body
= parse_block_expr ();
8253 if (body
== nullptr)
8255 Error
error (lexer
.peek_token ()->get_locus (),
8256 "failed to parse block expr (loop body) of while let loop");
8257 add_error (std::move (error
));
8263 return std::unique_ptr
<AST::WhileLetLoopExpr
> (new AST::WhileLetLoopExpr (
8264 std::move (predicate_patterns
), std::move (predicate_expr
),
8265 std::move (body
), locus
, std::move (label
), std::move (outer_attrs
)));
8268 /* Parses a "for" iterative loop. Label is not parsed and should be parsed via
8269 * parse_labelled_loop_expr, which would call this. */
8270 template <typename ManagedTokenSource
>
8271 std::unique_ptr
<AST::ForLoopExpr
>
8272 Parser
<ManagedTokenSource
>::parse_for_loop_expr (AST::AttrVec outer_attrs
,
8273 AST::LoopLabel label
)
8275 Location locus
= Linemap::unknown_location ();
8276 if (label
.is_error ())
8277 locus
= lexer
.peek_token ()->get_locus ();
8279 locus
= label
.get_locus ();
8282 // parse pattern, which is required
8283 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
8284 if (pattern
== nullptr)
8286 Error
error (lexer
.peek_token ()->get_locus (),
8287 "failed to parse iterator pattern in for loop");
8288 add_error (std::move (error
));
8294 if (!skip_token (IN
))
8300 /* parse iterator expression, which is required - also HACK to prevent
8302 ParseRestrictions no_struct_expr
;
8303 no_struct_expr
.can_be_struct_expr
= false;
8304 std::unique_ptr
<AST::Expr
> expr
= parse_expr ({}, no_struct_expr
);
8305 if (expr
== nullptr)
8307 Error
error (lexer
.peek_token ()->get_locus (),
8308 "failed to parse iterator expression in for loop");
8309 add_error (std::move (error
));
8314 // TODO: check to ensure this isn't struct expr? Or in semantic analysis.
8316 // parse loop body, which is required
8317 std::unique_ptr
<AST::BlockExpr
> body
= parse_block_expr ();
8318 if (body
== nullptr)
8320 Error
error (lexer
.peek_token ()->get_locus (),
8321 "failed to parse loop body block expression in for loop");
8322 add_error (std::move (error
));
8328 return std::unique_ptr
<AST::ForLoopExpr
> (
8329 new AST::ForLoopExpr (std::move (pattern
), std::move (expr
),
8330 std::move (body
), locus
, std::move (label
),
8331 std::move (outer_attrs
)));
8334 // Parses a loop expression with label (any kind of loop - disambiguates).
8335 template <typename ManagedTokenSource
>
8336 std::unique_ptr
<AST::BaseLoopExpr
>
8337 Parser
<ManagedTokenSource
>::parse_labelled_loop_expr (AST::AttrVec outer_attrs
)
8339 /* TODO: decide whether it should not work if there is no label, or parse it
8340 * with no label at the moment, I will make it not work with no label
8341 * because that's the implication. */
8343 if (lexer
.peek_token ()->get_id () != LIFETIME
)
8345 Error
error (lexer
.peek_token ()->get_locus (),
8346 "expected lifetime in labelled loop expr (to parse loop "
8347 "label) - found %qs",
8348 lexer
.peek_token ()->get_token_description ());
8349 add_error (std::move (error
));
8355 // parse loop label (required)
8356 AST::LoopLabel label
= parse_loop_label ();
8357 if (label
.is_error ())
8359 Error
error (lexer
.peek_token ()->get_locus (),
8360 "failed to parse loop label in labelled loop expr");
8361 add_error (std::move (error
));
8367 // branch on next token
8368 const_TokenPtr t
= lexer
.peek_token ();
8369 switch (t
->get_id ())
8372 return parse_loop_expr (std::move (outer_attrs
), std::move (label
));
8374 return parse_for_loop_expr (std::move (outer_attrs
), std::move (label
));
8376 // further disambiguate into while vs while let
8377 if (lexer
.peek_token (1)->get_id () == LET
)
8379 return parse_while_let_loop_expr (std::move (outer_attrs
),
8384 return parse_while_loop_expr (std::move (outer_attrs
),
8389 add_error (Error (t
->get_locus (),
8390 "unexpected token %qs when parsing labelled loop",
8391 t
->get_token_description ()));
8398 // Parses a match expression.
8399 template <typename ManagedTokenSource
>
8400 std::unique_ptr
<AST::MatchExpr
>
8401 Parser
<ManagedTokenSource
>::parse_match_expr (AST::AttrVec outer_attrs
,
8402 Location pratt_parsed_loc
)
8404 Location locus
= pratt_parsed_loc
;
8405 if (locus
== Linemap::unknown_location ())
8407 locus
= lexer
.peek_token ()->get_locus ();
8408 skip_token (MATCH_TOK
);
8411 /* parse scrutinee expression, which is required (and HACK to prevent struct
8413 ParseRestrictions no_struct_expr
;
8414 no_struct_expr
.can_be_struct_expr
= false;
8415 std::unique_ptr
<AST::Expr
> scrutinee
= parse_expr ({}, no_struct_expr
);
8416 if (scrutinee
== nullptr)
8418 Error
error (lexer
.peek_token ()->get_locus (),
8419 "failed to parse scrutinee expression in match expression");
8420 add_error (std::move (error
));
8425 /* TODO: check for scrutinee expr not being struct expr? or do so in
8426 * semantic analysis */
8428 if (!skip_token (LEFT_CURLY
))
8434 // parse inner attributes (if they exist)
8435 AST::AttrVec inner_attrs
= parse_inner_attributes ();
8437 // parse match arms (if they exist)
8438 // std::vector<std::unique_ptr<AST::MatchCase> > match_arms;
8439 std::vector
<AST::MatchCase
> match_arms
;
8441 // parse match cases
8442 while (lexer
.peek_token ()->get_id () != RIGHT_CURLY
)
8444 // parse match arm itself, which is required
8445 AST::MatchArm arm
= parse_match_arm ();
8446 if (arm
.is_error ())
8448 // TODO is this worth throwing everything away?
8449 Error
error (lexer
.peek_token ()->get_locus (),
8450 "failed to parse match arm in match arms");
8451 add_error (std::move (error
));
8456 if (!skip_token (MATCH_ARROW
))
8458 // skip after somewhere?
8459 // TODO is returning here a good idea? or is break better?
8463 ParseRestrictions restrictions
;
8464 restrictions
.expr_can_be_stmt
= true;
8465 restrictions
.consume_semi
= false;
8467 std::unique_ptr
<AST::ExprStmt
> expr
= parse_expr_stmt ({}, restrictions
);
8468 if (expr
== nullptr)
8470 Error
error (lexer
.peek_token ()->get_locus (),
8471 "failed to parse expr in match arm in match expr");
8472 add_error (std::move (error
));
8477 bool is_expr_without_block
8478 = expr
->get_type () == AST::ExprStmt::ExprStmtType::WITHOUT_BLOCK
;
8480 // construct match case expr and add to cases
8481 switch (expr
->get_type ())
8483 case AST::ExprStmt::ExprStmtType::WITH_BLOCK
: {
8484 AST::ExprStmtWithBlock
*cast
8485 = static_cast<AST::ExprStmtWithBlock
*> (expr
.get ());
8486 std::unique_ptr
<AST::Expr
> e
= cast
->get_expr ()->clone_expr ();
8487 match_arms
.push_back (
8488 AST::MatchCase (std::move (arm
), std::move (e
)));
8492 case AST::ExprStmt::ExprStmtType::WITHOUT_BLOCK
: {
8493 AST::ExprStmtWithoutBlock
*cast
8494 = static_cast<AST::ExprStmtWithoutBlock
*> (expr
.get ());
8495 std::unique_ptr
<AST::Expr
> e
= cast
->get_expr ()->clone_expr ();
8496 match_arms
.push_back (
8497 AST::MatchCase (std::move (arm
), std::move (e
)));
8502 // handle comma presence
8503 if (lexer
.peek_token ()->get_id () != COMMA
)
8505 if (!is_expr_without_block
)
8507 // allowed even if not final case
8510 else if (is_expr_without_block
8511 && lexer
.peek_token ()->get_id () != RIGHT_CURLY
)
8513 // not allowed if not final case
8514 Error
error (lexer
.peek_token ()->get_locus (),
8515 "exprwithoutblock requires comma after match case "
8516 "expression in match arm (if not final case)");
8517 add_error (std::move (error
));
8523 // otherwise, must be final case, so fine
8527 lexer
.skip_token ();
8530 if (!skip_token (RIGHT_CURLY
))
8536 match_arms
.shrink_to_fit ();
8538 return std::unique_ptr
<AST::MatchExpr
> (
8539 new AST::MatchExpr (std::move (scrutinee
), std::move (match_arms
),
8540 std::move (inner_attrs
), std::move (outer_attrs
),
8544 // Parses the "pattern" part of the match arm (the 'case x:' equivalent).
8545 template <typename ManagedTokenSource
>
8547 Parser
<ManagedTokenSource
>::parse_match_arm ()
8549 // parse optional outer attributes
8550 AST::AttrVec outer_attrs
= parse_outer_attributes ();
8553 rust_debug ("about to start parsing match arm patterns");
8555 // break early if find right curly
8556 if (lexer
.peek_token ()->get_id () == RIGHT_CURLY
)
8559 return AST::MatchArm::create_error ();
8562 // parse match arm patterns - at least 1 is required
8563 std::vector
<std::unique_ptr
<AST::Pattern
>> match_arm_patterns
8564 = parse_match_arm_patterns (RIGHT_CURLY
);
8565 if (match_arm_patterns
.empty ())
8567 Error
error (lexer
.peek_token ()->get_locus (),
8568 "failed to parse any patterns in match arm");
8569 add_error (std::move (error
));
8572 return AST::MatchArm::create_error ();
8576 rust_debug ("successfully parsed match arm patterns");
8578 // parse match arm guard expr if it exists
8579 std::unique_ptr
<AST::Expr
> guard_expr
= nullptr;
8580 if (lexer
.peek_token ()->get_id () == IF
)
8582 lexer
.skip_token ();
8584 guard_expr
= parse_expr ();
8585 if (guard_expr
== nullptr)
8587 Error
error (lexer
.peek_token ()->get_locus (),
8588 "failed to parse guard expression in match arm");
8589 add_error (std::move (error
));
8592 return AST::MatchArm::create_error ();
8597 rust_debug ("successfully parsed match arm");
8599 return AST::MatchArm (std::move (match_arm_patterns
),
8600 lexer
.peek_token ()->get_locus (),
8601 std::move (guard_expr
), std::move (outer_attrs
));
8604 /* Parses the patterns used in a match arm. End token id is the id of the
8605 * token that would exist after the patterns are done (e.g. '}' for match
8606 * expr, '=' for if let and while let). */
8607 template <typename ManagedTokenSource
>
8608 std::vector
<std::unique_ptr
<AST::Pattern
>>
8609 Parser
<ManagedTokenSource
>::parse_match_arm_patterns (TokenId end_token_id
)
8611 // skip optional leading '|'
8612 if (lexer
.peek_token ()->get_id () == PIPE
)
8613 lexer
.skip_token ();
8614 /* TODO: do I even need to store the result of this? can't be used.
8615 * If semantically different, I need a wrapped "match arm patterns" object
8618 std::vector
<std::unique_ptr
<AST::Pattern
>> patterns
;
8620 // quick break out if end_token_id
8621 if (lexer
.peek_token ()->get_id () == end_token_id
)
8624 // parse required pattern - if doesn't exist, return empty
8625 std::unique_ptr
<AST::Pattern
> initial_pattern
= parse_pattern ();
8626 if (initial_pattern
== nullptr)
8628 // FIXME: should this be an error?
8631 patterns
.push_back (std::move (initial_pattern
));
8634 rust_debug ("successfully parsed initial match arm pattern");
8636 // parse new patterns as long as next char is '|'
8637 const_TokenPtr t
= lexer
.peek_token ();
8638 while (t
->get_id () == PIPE
)
8641 lexer
.skip_token ();
8643 // break if hit end token id
8644 if (lexer
.peek_token ()->get_id () == end_token_id
)
8648 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
8649 if (pattern
== nullptr)
8652 Error
error (lexer
.peek_token ()->get_locus (),
8653 "failed to parse pattern in match arm patterns");
8654 add_error (std::move (error
));
8660 patterns
.push_back (std::move (pattern
));
8662 t
= lexer
.peek_token ();
8665 patterns
.shrink_to_fit ();
8670 // Parses an async block expression.
8671 template <typename ManagedTokenSource
>
8672 std::unique_ptr
<AST::AsyncBlockExpr
>
8673 Parser
<ManagedTokenSource
>::parse_async_block_expr (AST::AttrVec outer_attrs
)
8675 Location locus
= lexer
.peek_token ()->get_locus ();
8678 // detect optional move token
8679 bool has_move
= false;
8680 if (lexer
.peek_token ()->get_id () == MOVE
)
8682 lexer
.skip_token ();
8686 // parse block expression (required)
8687 std::unique_ptr
<AST::BlockExpr
> block_expr
= parse_block_expr ();
8688 if (block_expr
== nullptr)
8691 lexer
.peek_token ()->get_locus (),
8692 "failed to parse block expression of async block expression");
8693 add_error (std::move (error
));
8699 return std::unique_ptr
<AST::AsyncBlockExpr
> (
8700 new AST::AsyncBlockExpr (std::move (block_expr
), has_move
,
8701 std::move (outer_attrs
), locus
));
8704 // Parses an unsafe block expression.
8705 template <typename ManagedTokenSource
>
8706 std::unique_ptr
<AST::UnsafeBlockExpr
>
8707 Parser
<ManagedTokenSource
>::parse_unsafe_block_expr (AST::AttrVec outer_attrs
,
8708 Location pratt_parsed_loc
)
8710 Location locus
= pratt_parsed_loc
;
8711 if (locus
== Linemap::unknown_location ())
8713 locus
= lexer
.peek_token ()->get_locus ();
8714 skip_token (UNSAFE
);
8717 // parse block expression (required)
8718 std::unique_ptr
<AST::BlockExpr
> block_expr
= parse_block_expr ();
8719 if (block_expr
== nullptr)
8722 lexer
.peek_token ()->get_locus (),
8723 "failed to parse block expression of unsafe block expression");
8724 add_error (std::move (error
));
8730 return std::unique_ptr
<AST::UnsafeBlockExpr
> (
8731 new AST::UnsafeBlockExpr (std::move (block_expr
), std::move (outer_attrs
),
8735 // Parses an array definition expression.
8736 template <typename ManagedTokenSource
>
8737 std::unique_ptr
<AST::ArrayExpr
>
8738 Parser
<ManagedTokenSource
>::parse_array_expr (AST::AttrVec outer_attrs
,
8739 Location pratt_parsed_loc
)
8741 Location locus
= pratt_parsed_loc
;
8742 if (locus
== Linemap::unknown_location ())
8744 locus
= lexer
.peek_token ()->get_locus ();
8745 skip_token (LEFT_SQUARE
);
8748 // parse optional inner attributes
8749 AST::AttrVec inner_attrs
= parse_inner_attributes ();
8751 // parse the "array elements" section, which is optional
8752 if (lexer
.peek_token ()->get_id () == RIGHT_SQUARE
)
8754 // no array elements
8755 lexer
.skip_token ();
8757 std::vector
<std::unique_ptr
<AST::Expr
>> exprs
;
8759 = Rust::make_unique
<AST::ArrayElemsValues
> (std::move (exprs
), locus
);
8760 return Rust::make_unique
<AST::ArrayExpr
> (std::move (array_elems
),
8761 std::move (inner_attrs
),
8762 std::move (outer_attrs
), locus
);
8766 // should have array elements
8767 // parse initial expression, which is required for either
8768 std::unique_ptr
<AST::Expr
> initial_expr
= parse_expr ();
8769 if (initial_expr
== nullptr)
8771 Error
error (lexer
.peek_token ()->get_locus (),
8772 "could not parse expression in array expression "
8773 "(even though arrayelems seems to be present)");
8774 add_error (std::move (error
));
8780 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
8783 lexer
.skip_token ();
8785 // parse copy amount expression (required)
8786 std::unique_ptr
<AST::Expr
> copy_amount
= parse_expr ();
8787 if (copy_amount
== nullptr)
8789 Error
error (lexer
.peek_token ()->get_locus (),
8790 "could not parse copy amount expression in array "
8791 "expression (arrayelems)");
8792 add_error (std::move (error
));
8798 skip_token (RIGHT_SQUARE
);
8800 std::unique_ptr
<AST::ArrayElemsCopied
> copied_array_elems (
8801 new AST::ArrayElemsCopied (std::move (initial_expr
),
8802 std::move (copy_amount
), locus
));
8803 return std::unique_ptr
<AST::ArrayExpr
> (
8804 new AST::ArrayExpr (std::move (copied_array_elems
),
8805 std::move (inner_attrs
),
8806 std::move (outer_attrs
), locus
));
8808 else if (lexer
.peek_token ()->get_id () == RIGHT_SQUARE
)
8810 // single-element array expression
8811 std::vector
<std::unique_ptr
<AST::Expr
>> exprs
;
8813 exprs
.push_back (std::move (initial_expr
));
8814 exprs
.shrink_to_fit ();
8816 skip_token (RIGHT_SQUARE
);
8818 std::unique_ptr
<AST::ArrayElemsValues
> array_elems (
8819 new AST::ArrayElemsValues (std::move (exprs
), locus
));
8820 return std::unique_ptr
<AST::ArrayExpr
> (
8821 new AST::ArrayExpr (std::move (array_elems
),
8822 std::move (inner_attrs
),
8823 std::move (outer_attrs
), locus
));
8825 else if (lexer
.peek_token ()->get_id () == COMMA
)
8827 // multi-element array expression (or trailing comma)
8828 std::vector
<std::unique_ptr
<AST::Expr
>> exprs
;
8829 exprs
.push_back (std::move (initial_expr
));
8831 const_TokenPtr t
= lexer
.peek_token ();
8832 while (t
->get_id () == COMMA
)
8834 lexer
.skip_token ();
8836 // quick break if right square bracket
8837 if (lexer
.peek_token ()->get_id () == RIGHT_SQUARE
)
8840 // parse expression (required)
8841 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
8842 if (expr
== nullptr)
8844 Error
error (lexer
.peek_token ()->get_locus (),
8845 "failed to parse element in array expression");
8846 add_error (std::move (error
));
8851 exprs
.push_back (std::move (expr
));
8853 t
= lexer
.peek_token ();
8856 skip_token (RIGHT_SQUARE
);
8858 exprs
.shrink_to_fit ();
8860 std::unique_ptr
<AST::ArrayElemsValues
> array_elems (
8861 new AST::ArrayElemsValues (std::move (exprs
), locus
));
8862 return std::unique_ptr
<AST::ArrayExpr
> (
8863 new AST::ArrayExpr (std::move (array_elems
),
8864 std::move (inner_attrs
),
8865 std::move (outer_attrs
), locus
));
8870 Error
error (lexer
.peek_token ()->get_locus (),
8871 "unexpected token %qs in array expression (arrayelems)",
8872 lexer
.peek_token ()->get_token_description ());
8873 add_error (std::move (error
));
8881 // Parses a single parameter used in a closure definition.
8882 template <typename ManagedTokenSource
>
8884 Parser
<ManagedTokenSource
>::parse_closure_param ()
8886 AST::AttrVec outer_attrs
= parse_outer_attributes ();
8888 // parse pattern (which is required)
8889 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
8890 if (pattern
== nullptr)
8892 // not necessarily an error
8893 return AST::ClosureParam::create_error ();
8896 // parse optional type of param
8897 std::unique_ptr
<AST::Type
> type
= nullptr;
8898 if (lexer
.peek_token ()->get_id () == COLON
)
8900 lexer
.skip_token ();
8902 // parse type, which is now required
8903 type
= parse_type ();
8904 if (type
== nullptr)
8906 Error
error (lexer
.peek_token ()->get_locus (),
8907 "failed to parse type in closure parameter");
8908 add_error (std::move (error
));
8911 return AST::ClosureParam::create_error ();
8915 Location loc
= pattern
->get_locus ();
8916 return AST::ClosureParam (std::move (pattern
), loc
, std::move (type
),
8917 std::move (outer_attrs
));
8920 // Parses a grouped or tuple expression (disambiguates).
8921 template <typename ManagedTokenSource
>
8922 std::unique_ptr
<AST::ExprWithoutBlock
>
8923 Parser
<ManagedTokenSource
>::parse_grouped_or_tuple_expr (
8924 AST::AttrVec outer_attrs
, Location pratt_parsed_loc
)
8926 // adjustment to allow Pratt parsing to reuse function without copy-paste
8927 Location locus
= pratt_parsed_loc
;
8928 if (locus
== Linemap::unknown_location ())
8930 locus
= lexer
.peek_token ()->get_locus ();
8931 skip_token (LEFT_PAREN
);
8934 // parse optional inner attributes
8935 AST::AttrVec inner_attrs
= parse_inner_attributes ();
8937 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
8939 // must be empty tuple
8940 lexer
.skip_token ();
8942 // create tuple with empty tuple elems
8943 return std::unique_ptr
<AST::TupleExpr
> (
8944 new AST::TupleExpr (std::vector
<std::unique_ptr
<AST::Expr
>> (),
8945 std::move (inner_attrs
), std::move (outer_attrs
),
8949 // parse first expression (required)
8950 std::unique_ptr
<AST::Expr
> first_expr
= parse_expr ();
8951 if (first_expr
== nullptr)
8953 Error
error (lexer
.peek_token ()->get_locus (),
8954 "failed to parse expression in grouped or tuple expression");
8955 add_error (std::move (error
));
8957 // skip after somewhere?
8961 // detect whether grouped expression with right parentheses as next token
8962 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
8964 // must be grouped expr
8965 lexer
.skip_token ();
8967 // create grouped expr
8968 return std::unique_ptr
<AST::GroupedExpr
> (
8969 new AST::GroupedExpr (std::move (first_expr
), std::move (inner_attrs
),
8970 std::move (outer_attrs
), locus
));
8972 else if (lexer
.peek_token ()->get_id () == COMMA
)
8975 std::vector
<std::unique_ptr
<AST::Expr
>> exprs
;
8976 exprs
.push_back (std::move (first_expr
));
8978 // parse potential other tuple exprs
8979 const_TokenPtr t
= lexer
.peek_token ();
8980 while (t
->get_id () == COMMA
)
8982 lexer
.skip_token ();
8984 // break out if right paren
8985 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
8988 // parse expr, which is now required
8989 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
8990 if (expr
== nullptr)
8992 Error
error (lexer
.peek_token ()->get_locus (),
8993 "failed to parse expr in tuple expr");
8994 add_error (std::move (error
));
8999 exprs
.push_back (std::move (expr
));
9001 t
= lexer
.peek_token ();
9005 skip_token (RIGHT_PAREN
);
9007 return std::unique_ptr
<AST::TupleExpr
> (
9008 new AST::TupleExpr (std::move (exprs
), std::move (inner_attrs
),
9009 std::move (outer_attrs
), locus
));
9014 const_TokenPtr t
= lexer
.peek_token ();
9015 Error
error (t
->get_locus (),
9016 "unexpected token %qs in grouped or tuple expression "
9017 "(parenthesised expression) - expected %<)%> for grouped "
9018 "expr and %<,%> for tuple expr",
9019 t
->get_token_description ());
9020 add_error (std::move (error
));
9027 // Parses a type (will further disambiguate any type).
9028 template <typename ManagedTokenSource
>
9029 std::unique_ptr
<AST::Type
>
9030 Parser
<ManagedTokenSource
>::parse_type (bool save_errors
)
9032 /* rules for all types:
9034 * SliceType: '[' Type ']'
9036 * MacroInvocation: SimplePath '!' DelimTokenTree
9037 * ParenthesisedType: '(' Type ')'
9038 * ImplTraitType: 'impl' TypeParamBounds
9039 * TypeParamBounds (not type) TypeParamBound ( '+' TypeParamBound )* '+'?
9040 * TypeParamBound Lifetime | TraitBound
9041 * ImplTraitTypeOneBound: 'impl' TraitBound
9042 * TraitObjectType: 'dyn'? TypeParamBounds
9043 * TraitObjectTypeOneBound: 'dyn'? TraitBound
9044 * TraitBound '?'? ForLifetimes? TypePath | '(' '?'?
9045 * ForLifetimes? TypePath ')' BareFunctionType: ForLifetimes?
9046 * FunctionQualifiers 'fn' etc. ForLifetimes (not type) 'for' '<'
9047 * LifetimeParams '>' FunctionQualifiers ( 'async' | 'const' )?
9049 * ('extern' abi?)? QualifiedPathInType: '<' Type ( 'as' TypePath )? '>'
9051 * '::' TypePathSegment )+ TypePath: '::'? TypePathSegment (
9052 * '::' TypePathSegment)* ArrayType: '[' Type ';' Expr ']'
9053 * ReferenceType: '&' Lifetime? 'mut'? TypeNoBounds
9054 * RawPointerType: '*' ( 'mut' | 'const' ) TypeNoBounds
9055 * TupleType: '(' Type etc. - regular tuple stuff. Also
9056 * regular tuple vs parenthesised precedence
9058 * Disambiguate between macro and type path via type path being parsed, and
9059 * then if '!' found, convert type path to simple path for macro. Usual
9060 * disambiguation for tuple vs parenthesised. For ImplTraitType and
9061 * TraitObjectType individual disambiguations, they seem more like "special
9062 * cases", so probably just try to parse the more general ImplTraitType or
9063 * TraitObjectType and return OneBound versions if they satisfy those
9066 const_TokenPtr t
= lexer
.peek_token ();
9067 switch (t
->get_id ())
9070 // never type - can't be macro as no path beforehand
9071 lexer
.skip_token ();
9072 return std::unique_ptr
<AST::NeverType
> (
9073 new AST::NeverType (t
->get_locus ()));
9075 // slice type or array type - requires further disambiguation
9076 return parse_slice_or_array_type ();
9078 // qualified path in type
9079 AST::QualifiedPathInType path
= parse_qualified_path_in_type ();
9080 if (path
.is_error ())
9084 Error
error (t
->get_locus (),
9085 "failed to parse qualified path in type");
9086 add_error (std::move (error
));
9091 return std::unique_ptr
<AST::QualifiedPathInType
> (
9092 new AST::QualifiedPathInType (std::move (path
)));
9096 lexer
.skip_token ();
9097 return std::unique_ptr
<AST::InferredType
> (
9098 new AST::InferredType (t
->get_locus ()));
9101 return parse_raw_pointer_type ();
9102 case AMP
: // does this also include AMP_AMP?
9104 return parse_reference_type ();
9106 /* probably a lifetime bound, so probably type param bounds in
9107 * TraitObjectType */
9108 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
9109 = parse_type_param_bounds ();
9111 return std::unique_ptr
<AST::TraitObjectType
> (
9112 new AST::TraitObjectType (std::move (bounds
), t
->get_locus (),
9121 case SCOPE_RESOLUTION
: {
9122 // macro invocation or type path - requires further disambiguation.
9123 /* for parsing path component of each rule, perhaps parse it as a
9124 * typepath and attempt conversion to simplepath if a trailing '!' is
9126 /* Type path also includes TraitObjectTypeOneBound BUT if it starts
9127 * with it, it is exactly the same as a TypePath syntactically, so
9128 * this is a syntactical ambiguity. As such, the parser will parse it
9129 * as a TypePath. This, however, does not prevent TraitObjectType from
9130 * starting with a typepath. */
9132 // parse path as type path
9133 AST::TypePath path
= parse_type_path ();
9134 if (path
.is_error ())
9138 Error
error (t
->get_locus (),
9139 "failed to parse path as first component of type");
9140 add_error (std::move (error
));
9145 Location locus
= path
.get_locus ();
9147 // branch on next token
9148 t
= lexer
.peek_token ();
9149 switch (t
->get_id ())
9153 // convert to simple path
9154 AST::SimplePath macro_path
= path
.as_simple_path ();
9155 if (macro_path
.is_empty ())
9159 Error
error (t
->get_locus (),
9160 "failed to parse simple path in macro "
9161 "invocation (for type)");
9162 add_error (std::move (error
));
9168 lexer
.skip_token ();
9170 AST::DelimTokenTree tok_tree
= parse_delim_token_tree ();
9172 return std::unique_ptr
<AST::MacroInvocation
> (
9173 new AST::MacroInvocation (
9174 AST::MacroInvocData (std::move (macro_path
),
9175 std::move (tok_tree
)),
9179 // type param bounds
9180 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
9182 // convert type path to trait bound
9183 std::unique_ptr
<AST::TraitBound
> path_bound (
9184 new AST::TraitBound (std::move (path
), locus
, false, false));
9185 bounds
.push_back (std::move (path_bound
));
9187 /* parse rest of bounds - FIXME: better way to find when to stop
9189 while (t
->get_id () == PLUS
)
9191 lexer
.skip_token ();
9193 // parse bound if it exists - if not, assume end of sequence
9194 std::unique_ptr
<AST::TypeParamBound
> bound
9195 = parse_type_param_bound ();
9196 if (bound
== nullptr)
9200 bounds
.push_back (std::move (bound
));
9202 t
= lexer
.peek_token ();
9205 return std::unique_ptr
<AST::TraitObjectType
> (
9206 new AST::TraitObjectType (std::move (bounds
), locus
, false));
9209 // assume that this is a type path and not an error
9210 return std::unique_ptr
<AST::TypePath
> (
9211 new AST::TypePath (std::move (path
)));
9215 /* tuple type or parenthesised type - requires further disambiguation
9216 * (the usual). ok apparently can be a parenthesised TraitBound too, so
9217 * could be TraitObjectTypeOneBound or TraitObjectType */
9218 return parse_paren_prefixed_type ();
9220 // TraitObjectTypeOneBound or BareFunctionType
9221 return parse_for_prefixed_type ();
9227 // bare function type (with no for lifetimes)
9228 return parse_bare_function_type (std::vector
<AST::LifetimeParam
> ());
9230 lexer
.skip_token ();
9231 if (lexer
.peek_token ()->get_id () == LIFETIME
)
9233 /* cannot be one bound because lifetime prevents it from being
9235 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
9236 = parse_type_param_bounds ();
9238 return std::unique_ptr
<AST::ImplTraitType
> (
9239 new AST::ImplTraitType (std::move (bounds
), t
->get_locus ()));
9243 // should be trait bound, so parse trait bound
9244 std::unique_ptr
<AST::TraitBound
> initial_bound
= parse_trait_bound ();
9245 if (initial_bound
== nullptr)
9249 Error
error (lexer
.peek_token ()->get_locus (),
9250 "failed to parse ImplTraitType initial bound");
9251 add_error (std::move (error
));
9257 Location locus
= t
->get_locus ();
9259 // short cut if next token isn't '+'
9260 t
= lexer
.peek_token ();
9261 if (t
->get_id () != PLUS
)
9263 // convert trait bound to value object
9264 AST::TraitBound
value_bound (*initial_bound
);
9266 // DEBUG: removed as unique ptr, so should auto-delete
9267 // delete initial_bound;
9269 return std::unique_ptr
<AST::ImplTraitTypeOneBound
> (
9270 new AST::ImplTraitTypeOneBound (std::move (value_bound
),
9274 // parse additional type param bounds
9275 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
9276 bounds
.push_back (std::move (initial_bound
));
9277 while (t
->get_id () == PLUS
)
9279 lexer
.skip_token ();
9281 // parse bound if it exists
9282 std::unique_ptr
<AST::TypeParamBound
> bound
9283 = parse_type_param_bound ();
9284 if (bound
== nullptr)
9286 // not an error as trailing plus may exist
9289 bounds
.push_back (std::move (bound
));
9291 t
= lexer
.peek_token ();
9294 return std::unique_ptr
<AST::ImplTraitType
> (
9295 new AST::ImplTraitType (std::move (bounds
), locus
));
9298 case QUESTION_MARK
: {
9299 // either TraitObjectType or TraitObjectTypeOneBound
9300 bool has_dyn
= false;
9301 if (t
->get_id () == DYN
)
9303 lexer
.skip_token ();
9307 if (lexer
.peek_token ()->get_id () == LIFETIME
)
9309 /* cannot be one bound because lifetime prevents it from being
9311 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
9312 = parse_type_param_bounds ();
9314 return std::unique_ptr
<AST::TraitObjectType
> (
9315 new AST::TraitObjectType (std::move (bounds
), t
->get_locus (),
9320 // should be trait bound, so parse trait bound
9321 std::unique_ptr
<AST::TraitBound
> initial_bound
9322 = parse_trait_bound ();
9323 if (initial_bound
== nullptr)
9328 lexer
.peek_token ()->get_locus (),
9329 "failed to parse TraitObjectType initial bound");
9330 add_error (std::move (error
));
9336 // short cut if next token isn't '+'
9337 t
= lexer
.peek_token ();
9338 if (t
->get_id () != PLUS
)
9340 // convert trait bound to value object
9341 AST::TraitBound
value_bound (*initial_bound
);
9343 // DEBUG: removed as unique ptr, so should auto delete
9344 // delete initial_bound;
9346 return std::unique_ptr
<AST::TraitObjectTypeOneBound
> (
9347 new AST::TraitObjectTypeOneBound (std::move (value_bound
),
9348 t
->get_locus (), has_dyn
));
9351 // parse additional type param bounds
9352 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
9353 bounds
.push_back (std::move (initial_bound
));
9354 while (t
->get_id () == PLUS
)
9356 lexer
.skip_token ();
9358 // parse bound if it exists
9359 std::unique_ptr
<AST::TypeParamBound
> bound
9360 = parse_type_param_bound ();
9361 if (bound
== nullptr)
9363 // not an error as trailing plus may exist
9366 bounds
.push_back (std::move (bound
));
9368 t
= lexer
.peek_token ();
9371 return std::unique_ptr
<AST::TraitObjectType
> (
9372 new AST::TraitObjectType (std::move (bounds
), t
->get_locus (),
9378 add_error (Error (t
->get_locus (), "unrecognised token %qs in type",
9379 t
->get_token_description ()));
9385 /* Parses a type that has '(' as its first character. Returns a tuple type,
9386 * parenthesised type, TraitObjectTypeOneBound, or TraitObjectType depending
9387 * on following characters. */
9388 template <typename ManagedTokenSource
>
9389 std::unique_ptr
<AST::Type
>
9390 Parser
<ManagedTokenSource
>::parse_paren_prefixed_type ()
9392 /* NOTE: Syntactical ambiguity of a parenthesised trait bound is considered
9393 * a trait bound, not a parenthesised type, so that it can still be used in
9394 * type param bounds. */
9396 /* NOTE: this implementation is really shit but I couldn't think of a better
9397 * one. It requires essentially breaking polymorphism and downcasting via
9398 * virtual method abuse, as it was copied from the rustc implementation (in
9399 * which types are reified due to tagged union), after a more OOP attempt by
9401 Location left_delim_locus
= lexer
.peek_token ()->get_locus ();
9404 lexer
.skip_token ();
9405 /* while next token isn't close delim, parse comma-separated types, saving
9406 * whether trailing comma happens */
9407 const_TokenPtr t
= lexer
.peek_token ();
9408 bool trailing_comma
= true;
9409 std::vector
<std::unique_ptr
<AST::Type
>> types
;
9411 while (t
->get_id () != RIGHT_PAREN
)
9413 std::unique_ptr
<AST::Type
> type
= parse_type ();
9414 if (type
== nullptr)
9416 Error
error (t
->get_locus (),
9417 "failed to parse type inside parentheses (probably "
9418 "tuple or parenthesised)");
9419 add_error (std::move (error
));
9423 types
.push_back (std::move (type
));
9425 t
= lexer
.peek_token ();
9426 if (t
->get_id () != COMMA
)
9428 trailing_comma
= false;
9431 lexer
.skip_token ();
9433 t
= lexer
.peek_token ();
9436 if (!skip_token (RIGHT_PAREN
))
9441 // if only one type and no trailing comma, then not a tuple type
9442 if (types
.size () == 1 && !trailing_comma
)
9444 // must be a TraitObjectType (with more than one bound)
9445 if (lexer
.peek_token ()->get_id () == PLUS
)
9447 // create type param bounds vector
9448 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
9450 // HACK: convert type to traitbound and add to bounds
9451 std::unique_ptr
<AST::Type
> released_ptr
= std::move (types
[0]);
9452 std::unique_ptr
<AST::TraitBound
> converted_bound (
9453 released_ptr
->to_trait_bound (true));
9454 if (converted_bound
== nullptr)
9457 lexer
.peek_token ()->get_locus (),
9458 "failed to hackily converted parsed type to trait bound");
9459 add_error (std::move (error
));
9463 bounds
.push_back (std::move (converted_bound
));
9465 t
= lexer
.peek_token ();
9466 while (t
->get_id () == PLUS
)
9468 lexer
.skip_token ();
9470 // attempt to parse typeparambound
9471 std::unique_ptr
<AST::TypeParamBound
> bound
9472 = parse_type_param_bound ();
9473 if (bound
== nullptr)
9475 // not an error if null
9478 bounds
.push_back (std::move (bound
));
9480 t
= lexer
.peek_token ();
9483 return std::unique_ptr
<AST::TraitObjectType
> (
9484 new AST::TraitObjectType (std::move (bounds
), left_delim_locus
,
9489 // release vector pointer
9490 std::unique_ptr
<AST::Type
> released_ptr
= std::move (types
[0]);
9491 /* HACK: attempt to convert to trait bound. if fails, parenthesised
9493 std::unique_ptr
<AST::TraitBound
> converted_bound (
9494 released_ptr
->to_trait_bound (true));
9495 if (converted_bound
== nullptr)
9497 // parenthesised type
9498 return std::unique_ptr
<AST::ParenthesisedType
> (
9499 new AST::ParenthesisedType (std::move (released_ptr
),
9504 // trait object type (one bound)
9506 // get value semantics trait bound
9507 AST::TraitBound
value_bound (*converted_bound
);
9509 return std::unique_ptr
<AST::TraitObjectTypeOneBound
> (
9510 new AST::TraitObjectTypeOneBound (value_bound
,
9517 return std::unique_ptr
<AST::TupleType
> (
9518 new AST::TupleType (std::move (types
), left_delim_locus
));
9520 /* TODO: ensure that this ensures that dynamic dispatch for traits is not
9524 /* Parses a type that has 'for' as its first character. This means it has a
9525 * "for lifetimes", so returns either a BareFunctionType, TraitObjectType, or
9526 * TraitObjectTypeOneBound depending on following characters. */
9527 template <typename ManagedTokenSource
>
9528 std::unique_ptr
<AST::Type
>
9529 Parser
<ManagedTokenSource
>::parse_for_prefixed_type ()
9531 Location for_locus
= lexer
.peek_token ()->get_locus ();
9532 // parse for lifetimes in type
9533 std::vector
<AST::LifetimeParam
> for_lifetimes
= parse_for_lifetimes ();
9535 // branch on next token - either function or a trait type
9536 const_TokenPtr t
= lexer
.peek_token ();
9537 switch (t
->get_id ())
9544 return parse_bare_function_type (std::move (for_lifetimes
));
9545 case SCOPE_RESOLUTION
:
9552 // path, so trait type
9554 // parse type path to finish parsing trait bound
9555 AST::TypePath path
= parse_type_path ();
9557 t
= lexer
.peek_token ();
9558 if (t
->get_id () != PLUS
)
9560 // must be one-bound trait type
9561 // create trait bound value object
9562 AST::TraitBound
bound (std::move (path
), for_locus
, false, false,
9563 std::move (for_lifetimes
));
9565 return std::unique_ptr
<AST::TraitObjectTypeOneBound
> (
9566 new AST::TraitObjectTypeOneBound (std::move (bound
), for_locus
));
9569 /* more than one bound trait type (or at least parsed as it - could be
9570 * trailing '+') create trait bound pointer and bounds */
9571 std::unique_ptr
<AST::TraitBound
> initial_bound (
9572 new AST::TraitBound (std::move (path
), for_locus
, false, false,
9573 std::move (for_lifetimes
)));
9574 std::vector
<std::unique_ptr
<AST::TypeParamBound
>> bounds
;
9575 bounds
.push_back (std::move (initial_bound
));
9577 while (t
->get_id () == PLUS
)
9579 lexer
.skip_token ();
9581 // parse type param bound if it exists
9582 std::unique_ptr
<AST::TypeParamBound
> bound
9583 = parse_type_param_bound ();
9584 if (bound
== nullptr)
9586 // not an error - e.g. trailing plus
9589 bounds
.push_back (std::move (bound
));
9591 t
= lexer
.peek_token ();
9594 return std::unique_ptr
<AST::TraitObjectType
> (
9595 new AST::TraitObjectType (std::move (bounds
), for_locus
, false));
9599 add_error (Error (t
->get_locus (),
9600 "unrecognised token %qs in bare function type or trait "
9601 "object type or trait object type one bound",
9602 t
->get_token_description ()));
9608 // Parses a maybe named param used in bare function types.
9609 template <typename ManagedTokenSource
>
9610 AST::MaybeNamedParam
9611 Parser
<ManagedTokenSource
>::parse_maybe_named_param (AST::AttrVec outer_attrs
)
9613 /* Basically guess that param is named if first token is identifier or
9614 * underscore and second token is semicolon. This should probably have no
9615 * exceptions. rustc uses backtracking to parse these, but at the time of
9616 * writing gccrs has no backtracking capabilities. */
9617 const_TokenPtr current
= lexer
.peek_token ();
9618 const_TokenPtr next
= lexer
.peek_token (1);
9621 AST::MaybeNamedParam::ParamKind kind
= AST::MaybeNamedParam::UNNAMED
;
9623 if (current
->get_id () == IDENTIFIER
&& next
->get_id () == COLON
)
9626 name
= current
->get_str ();
9627 kind
= AST::MaybeNamedParam::IDENTIFIER
;
9628 lexer
.skip_token (1);
9630 else if (current
->get_id () == UNDERSCORE
&& next
->get_id () == COLON
)
9634 kind
= AST::MaybeNamedParam::WILDCARD
;
9635 lexer
.skip_token (1);
9638 // parse type (required)
9639 std::unique_ptr
<AST::Type
> type
= parse_type ();
9640 if (type
== nullptr)
9642 Error
error (lexer
.peek_token ()->get_locus (),
9643 "failed to parse type in maybe named param");
9644 add_error (std::move (error
));
9646 return AST::MaybeNamedParam::create_error ();
9649 return AST::MaybeNamedParam (std::move (name
), kind
, std::move (type
),
9650 std::move (outer_attrs
), current
->get_locus ());
9653 /* Parses a bare function type (with the given for lifetimes for convenience -
9654 * does not parse them itself). */
9655 template <typename ManagedTokenSource
>
9656 std::unique_ptr
<AST::BareFunctionType
>
9657 Parser
<ManagedTokenSource
>::parse_bare_function_type (
9658 std::vector
<AST::LifetimeParam
> for_lifetimes
)
9660 // TODO: pass in for lifetime location as param
9661 Location best_try_locus
= lexer
.peek_token ()->get_locus ();
9663 AST::FunctionQualifiers qualifiers
= parse_function_qualifiers ();
9665 if (!skip_token (FN_TOK
))
9668 if (!skip_token (LEFT_PAREN
))
9671 // parse function params, if they exist
9672 std::vector
<AST::MaybeNamedParam
> params
;
9673 bool is_variadic
= false;
9674 AST::AttrVec variadic_attrs
;
9676 const_TokenPtr t
= lexer
.peek_token ();
9677 while (t
->get_id () != RIGHT_PAREN
)
9679 AST::AttrVec temp_attrs
= parse_outer_attributes ();
9681 if (lexer
.peek_token ()->get_id () == ELLIPSIS
)
9683 lexer
.skip_token ();
9685 variadic_attrs
= std::move (temp_attrs
);
9687 t
= lexer
.peek_token ();
9689 if (t
->get_id () != RIGHT_PAREN
)
9691 Error
error (t
->get_locus (),
9692 "expected right parentheses after variadic in maybe "
9694 "parameters, found %qs",
9695 t
->get_token_description ());
9696 add_error (std::move (error
));
9704 AST::MaybeNamedParam param
9705 = parse_maybe_named_param (std::move (temp_attrs
));
9706 if (param
.is_error ())
9709 lexer
.peek_token ()->get_locus (),
9710 "failed to parse maybe named param in bare function type");
9711 add_error (std::move (error
));
9715 params
.push_back (std::move (param
));
9717 if (lexer
.peek_token ()->get_id () != COMMA
)
9720 lexer
.skip_token ();
9721 t
= lexer
.peek_token ();
9724 if (!skip_token (RIGHT_PAREN
))
9727 // bare function return type, if exists
9728 std::unique_ptr
<AST::TypeNoBounds
> return_type
= nullptr;
9729 if (lexer
.peek_token ()->get_id () == RETURN_TYPE
)
9731 lexer
.skip_token ();
9733 // parse required TypeNoBounds
9734 return_type
= parse_type_no_bounds ();
9735 if (return_type
== nullptr)
9737 Error
error (lexer
.peek_token ()->get_locus (),
9738 "failed to parse return type (type no bounds) in bare "
9740 add_error (std::move (error
));
9746 return std::unique_ptr
<AST::BareFunctionType
> (
9747 new AST::BareFunctionType (std::move (for_lifetimes
),
9748 std::move (qualifiers
), std::move (params
),
9749 is_variadic
, std::move (variadic_attrs
),
9750 std::move (return_type
), best_try_locus
));
9753 // Parses a reference type (mutable or immutable, with given lifetime).
9754 template <typename ManagedTokenSource
>
9755 std::unique_ptr
<AST::ReferenceType
>
9756 Parser
<ManagedTokenSource
>::parse_reference_type ()
9758 Location locus
= lexer
.peek_token ()->get_locus ();
9761 // parse optional lifetime
9762 AST::Lifetime lifetime
= AST::Lifetime::error ();
9763 if (lexer
.peek_token ()->get_id () == LIFETIME
)
9765 lifetime
= parse_lifetime ();
9766 if (lifetime
.is_error ())
9768 Error
error (lexer
.peek_token ()->get_locus (),
9769 "failed to parse lifetime in reference type");
9770 add_error (std::move (error
));
9776 bool is_mut
= false;
9777 if (lexer
.peek_token ()->get_id () == MUT
)
9779 lexer
.skip_token ();
9783 // parse type no bounds, which is required
9784 std::unique_ptr
<AST::TypeNoBounds
> type
= parse_type_no_bounds ();
9785 if (type
== nullptr)
9787 Error
error (lexer
.peek_token ()->get_locus (),
9788 "failed to parse referenced type in reference type");
9789 add_error (std::move (error
));
9794 return std::unique_ptr
<AST::ReferenceType
> (
9795 new AST::ReferenceType (is_mut
, std::move (type
), locus
,
9796 std::move (lifetime
)));
9799 // Parses a raw (unsafe) pointer type.
9800 template <typename ManagedTokenSource
>
9801 std::unique_ptr
<AST::RawPointerType
>
9802 Parser
<ManagedTokenSource
>::parse_raw_pointer_type ()
9804 Location locus
= lexer
.peek_token ()->get_locus ();
9805 skip_token (ASTERISK
);
9807 AST::RawPointerType::PointerType kind
= AST::RawPointerType::CONST
;
9809 // branch on next token for pointer kind info
9810 const_TokenPtr t
= lexer
.peek_token ();
9811 switch (t
->get_id ())
9814 kind
= AST::RawPointerType::MUT
;
9815 lexer
.skip_token ();
9818 kind
= AST::RawPointerType::CONST
;
9819 lexer
.skip_token ();
9822 add_error (Error (t
->get_locus (),
9823 "unrecognised token %qs in raw pointer type",
9824 t
->get_token_description ()));
9829 // parse type no bounds (required)
9830 std::unique_ptr
<AST::TypeNoBounds
> type
= parse_type_no_bounds ();
9831 if (type
== nullptr)
9833 Error
error (lexer
.peek_token ()->get_locus (),
9834 "failed to parse pointed type of raw pointer type");
9835 add_error (std::move (error
));
9840 return std::unique_ptr
<AST::RawPointerType
> (
9841 new AST::RawPointerType (kind
, std::move (type
), locus
));
9844 /* Parses a slice or array type, depending on following arguments (as
9845 * lookahead is not possible). */
9846 template <typename ManagedTokenSource
>
9847 std::unique_ptr
<AST::TypeNoBounds
>
9848 Parser
<ManagedTokenSource
>::parse_slice_or_array_type ()
9850 Location locus
= lexer
.peek_token ()->get_locus ();
9851 skip_token (LEFT_SQUARE
);
9853 // parse inner type (required)
9854 std::unique_ptr
<AST::Type
> inner_type
= parse_type ();
9855 if (inner_type
== nullptr)
9857 Error
error (lexer
.peek_token ()->get_locus (),
9858 "failed to parse inner type in slice or array type");
9859 add_error (std::move (error
));
9864 // branch on next token
9865 const_TokenPtr t
= lexer
.peek_token ();
9866 switch (t
->get_id ())
9870 lexer
.skip_token ();
9872 return std::unique_ptr
<AST::SliceType
> (
9873 new AST::SliceType (std::move (inner_type
), locus
));
9876 lexer
.skip_token ();
9878 // parse required array size expression
9879 std::unique_ptr
<AST::Expr
> size
= parse_expr ();
9880 if (size
== nullptr)
9882 Error
error (lexer
.peek_token ()->get_locus (),
9883 "failed to parse size expression in array type");
9884 add_error (std::move (error
));
9889 if (!skip_token (RIGHT_SQUARE
))
9894 return std::unique_ptr
<AST::ArrayType
> (
9895 new AST::ArrayType (std::move (inner_type
), std::move (size
), locus
));
9900 Error (t
->get_locus (),
9901 "unrecognised token %qs in slice or array type after inner type",
9902 t
->get_token_description ()));
9908 // Parses a type, taking into account type boundary disambiguation.
9909 template <typename ManagedTokenSource
>
9910 std::unique_ptr
<AST::TypeNoBounds
>
9911 Parser
<ManagedTokenSource
>::parse_type_no_bounds ()
9913 const_TokenPtr t
= lexer
.peek_token ();
9914 switch (t
->get_id ())
9917 // never type - can't be macro as no path beforehand
9918 lexer
.skip_token ();
9919 return std::unique_ptr
<AST::NeverType
> (
9920 new AST::NeverType (t
->get_locus ()));
9922 // slice type or array type - requires further disambiguation
9923 return parse_slice_or_array_type ();
9925 // qualified path in type
9926 AST::QualifiedPathInType path
= parse_qualified_path_in_type ();
9927 if (path
.is_error ())
9929 Error
error (t
->get_locus (),
9930 "failed to parse qualified path in type");
9931 add_error (std::move (error
));
9935 return std::unique_ptr
<AST::QualifiedPathInType
> (
9936 new AST::QualifiedPathInType (std::move (path
)));
9940 lexer
.skip_token ();
9941 return std::unique_ptr
<AST::InferredType
> (
9942 new AST::InferredType (t
->get_locus ()));
9945 return parse_raw_pointer_type ();
9946 case AMP
: // does this also include AMP_AMP?
9948 return parse_reference_type ();
9950 /* probably a lifetime bound, so probably type param bounds in
9951 * TraitObjectType. this is not allowed, but detection here for error
9953 add_error (Error (t
->get_locus (),
9954 "lifetime bounds (i.e. in type param bounds, in "
9955 "TraitObjectType) are not allowed as TypeNoBounds"));
9964 case SCOPE_RESOLUTION
: {
9965 // macro invocation or type path - requires further disambiguation.
9966 /* for parsing path component of each rule, perhaps parse it as a
9967 * typepath and attempt conversion to simplepath if a trailing '!' is
9969 /* Type path also includes TraitObjectTypeOneBound BUT if it starts
9970 * with it, it is exactly the same as a TypePath syntactically, so
9971 * this is a syntactical ambiguity. As such, the parser will parse it
9972 * as a TypePath. This, however, does not prevent TraitObjectType from
9973 * starting with a typepath. */
9975 // parse path as type path
9976 AST::TypePath path
= parse_type_path ();
9977 if (path
.is_error ())
9981 "failed to parse path as first component of type no bounds");
9982 add_error (std::move (error
));
9986 Location locus
= path
.get_locus ();
9988 // branch on next token
9989 t
= lexer
.peek_token ();
9990 switch (t
->get_id ())
9994 // convert to simple path
9995 AST::SimplePath macro_path
= path
.as_simple_path ();
9996 if (macro_path
.is_empty ())
9998 Error
error (t
->get_locus (),
9999 "failed to parse simple path in macro "
10000 "invocation (for type)");
10001 add_error (std::move (error
));
10006 lexer
.skip_token ();
10008 AST::DelimTokenTree tok_tree
= parse_delim_token_tree ();
10010 return std::unique_ptr
<AST::MacroInvocation
> (
10011 new AST::MacroInvocation (
10012 AST::MacroInvocData (std::move (macro_path
),
10013 std::move (tok_tree
)),
10017 // assume that this is a type path and not an error
10018 return std::unique_ptr
<AST::TypePath
> (
10019 new AST::TypePath (std::move (path
)));
10023 /* tuple type or parenthesised type - requires further disambiguation
10024 * (the usual). ok apparently can be a parenthesised TraitBound too, so
10025 * could be TraitObjectTypeOneBound */
10026 return parse_paren_prefixed_type_no_bounds ();
10033 // bare function type (with no for lifetimes)
10034 return parse_bare_function_type (std::vector
<AST::LifetimeParam
> ());
10036 lexer
.skip_token ();
10037 if (lexer
.peek_token ()->get_id () == LIFETIME
)
10039 /* cannot be one bound because lifetime prevents it from being
10040 * traitbound not allowed as type no bounds, only here for error
10043 lexer
.peek_token ()->get_locus (),
10044 "lifetime (probably lifetime bound, in type param "
10045 "bounds, in ImplTraitType) is not allowed in TypeNoBounds");
10046 add_error (std::move (error
));
10052 // should be trait bound, so parse trait bound
10053 std::unique_ptr
<AST::TraitBound
> initial_bound
= parse_trait_bound ();
10054 if (initial_bound
== nullptr)
10056 Error
error (lexer
.peek_token ()->get_locus (),
10057 "failed to parse ImplTraitTypeOneBound bound");
10058 add_error (std::move (error
));
10063 Location locus
= t
->get_locus ();
10065 // ensure not a trait with multiple bounds
10066 t
= lexer
.peek_token ();
10067 if (t
->get_id () == PLUS
)
10069 Error
error (t
->get_locus (),
10070 "plus after trait bound means an ImplTraitType, "
10071 "which is not allowed as a TypeNoBounds");
10072 add_error (std::move (error
));
10077 // convert trait bound to value object
10078 AST::TraitBound
value_bound (*initial_bound
);
10080 return std::unique_ptr
<AST::ImplTraitTypeOneBound
> (
10081 new AST::ImplTraitTypeOneBound (std::move (value_bound
), locus
));
10084 case QUESTION_MARK
: {
10085 // either TraitObjectTypeOneBound
10086 bool has_dyn
= false;
10087 if (t
->get_id () == DYN
)
10089 lexer
.skip_token ();
10093 if (lexer
.peek_token ()->get_id () == LIFETIME
)
10095 /* means that cannot be TraitObjectTypeOneBound - so here for
10097 Error
error (lexer
.peek_token ()->get_locus (),
10098 "lifetime as bound in TraitObjectTypeOneBound "
10099 "is not allowed, so cannot be TypeNoBounds");
10100 add_error (std::move (error
));
10105 // should be trait bound, so parse trait bound
10106 std::unique_ptr
<AST::TraitBound
> initial_bound
= parse_trait_bound ();
10107 if (initial_bound
== nullptr)
10110 lexer
.peek_token ()->get_locus (),
10111 "failed to parse TraitObjectTypeOneBound initial bound");
10112 add_error (std::move (error
));
10117 Location locus
= t
->get_locus ();
10119 // detect error with plus as next token
10120 t
= lexer
.peek_token ();
10121 if (t
->get_id () == PLUS
)
10123 Error
error (t
->get_locus (),
10124 "plus after trait bound means a TraitObjectType, "
10125 "which is not allowed as a TypeNoBounds");
10126 add_error (std::move (error
));
10131 // convert trait bound to value object
10132 AST::TraitBound
value_bound (*initial_bound
);
10134 return std::unique_ptr
<AST::TraitObjectTypeOneBound
> (
10135 new AST::TraitObjectTypeOneBound (std::move (value_bound
), locus
,
10139 add_error (Error (t
->get_locus (),
10140 "unrecognised token %qs in type no bounds",
10141 t
->get_token_description ()));
10147 // Parses a type no bounds beginning with '('.
10148 template <typename ManagedTokenSource
>
10149 std::unique_ptr
<AST::TypeNoBounds
>
10150 Parser
<ManagedTokenSource
>::parse_paren_prefixed_type_no_bounds ()
10152 /* NOTE: this could probably be parsed without the HACK solution of
10153 * parse_paren_prefixed_type, but I was lazy. So FIXME for future.*/
10155 /* NOTE: again, syntactical ambiguity of a parenthesised trait bound is
10156 * considered a trait bound, not a parenthesised type, so that it can still
10157 * be used in type param bounds. */
10159 Location left_paren_locus
= lexer
.peek_token ()->get_locus ();
10162 lexer
.skip_token ();
10163 /* while next token isn't close delim, parse comma-separated types, saving
10164 * whether trailing comma happens */
10165 const_TokenPtr t
= lexer
.peek_token ();
10166 bool trailing_comma
= true;
10167 std::vector
<std::unique_ptr
<AST::Type
>> types
;
10169 while (t
->get_id () != RIGHT_PAREN
)
10171 std::unique_ptr
<AST::Type
> type
= parse_type ();
10172 if (type
== nullptr)
10174 Error
error (t
->get_locus (),
10175 "failed to parse type inside parentheses (probably "
10176 "tuple or parenthesised)");
10177 add_error (std::move (error
));
10181 types
.push_back (std::move (type
));
10183 t
= lexer
.peek_token ();
10184 if (t
->get_id () != COMMA
)
10186 trailing_comma
= false;
10189 lexer
.skip_token ();
10191 t
= lexer
.peek_token ();
10194 if (!skip_token (RIGHT_PAREN
))
10199 // if only one type and no trailing comma, then not a tuple type
10200 if (types
.size () == 1 && !trailing_comma
)
10202 // must be a TraitObjectType (with more than one bound)
10203 if (lexer
.peek_token ()->get_id () == PLUS
)
10205 // error - this is not allowed for type no bounds
10206 Error
error (lexer
.peek_token ()->get_locus (),
10207 "plus (implying TraitObjectType as type param "
10208 "bounds) is not allowed in type no bounds");
10209 add_error (std::move (error
));
10215 // release vector pointer
10216 std::unique_ptr
<AST::Type
> released_ptr
= std::move (types
[0]);
10217 /* HACK: attempt to convert to trait bound. if fails, parenthesised
10219 std::unique_ptr
<AST::TraitBound
> converted_bound (
10220 released_ptr
->to_trait_bound (true));
10221 if (converted_bound
== nullptr)
10223 // parenthesised type
10224 return std::unique_ptr
<AST::ParenthesisedType
> (
10225 new AST::ParenthesisedType (std::move (released_ptr
),
10226 left_paren_locus
));
10230 // trait object type (one bound)
10232 // get value semantics trait bound
10233 AST::TraitBound
value_bound (*converted_bound
);
10235 return std::unique_ptr
<AST::TraitObjectTypeOneBound
> (
10236 new AST::TraitObjectTypeOneBound (value_bound
,
10237 left_paren_locus
));
10243 return std::unique_ptr
<AST::TupleType
> (
10244 new AST::TupleType (std::move (types
), left_paren_locus
));
10246 /* TODO: ensure that this ensures that dynamic dispatch for traits is not
10250 /* Parses a literal pattern or range pattern. Assumes that literals passed in
10251 * are valid range pattern bounds. Do not pass in paths in expressions, for
10253 template <typename ManagedTokenSource
>
10254 std::unique_ptr
<AST::Pattern
>
10255 Parser
<ManagedTokenSource
>::parse_literal_or_range_pattern ()
10257 const_TokenPtr range_lower
= lexer
.peek_token ();
10258 AST::Literal::LitType type
= AST::Literal::STRING
;
10259 bool has_minus
= false;
10262 switch (range_lower
->get_id ())
10265 type
= AST::Literal::CHAR
;
10266 lexer
.skip_token ();
10268 case BYTE_CHAR_LITERAL
:
10269 type
= AST::Literal::BYTE
;
10270 lexer
.skip_token ();
10273 type
= AST::Literal::INT
;
10274 lexer
.skip_token ();
10276 case FLOAT_LITERAL
:
10277 type
= AST::Literal::FLOAT
;
10278 lexer
.skip_token ();
10281 // branch on next token
10282 range_lower
= lexer
.peek_token (1);
10283 switch (range_lower
->get_id ())
10286 type
= AST::Literal::INT
;
10288 lexer
.skip_token (1);
10290 case FLOAT_LITERAL
:
10291 type
= AST::Literal::FLOAT
;
10293 lexer
.skip_token (1);
10296 add_error (Error (range_lower
->get_locus (),
10297 "token type %qs cannot be parsed as range pattern "
10298 "bound or literal after minus symbol",
10299 range_lower
->get_token_description ()));
10306 Error (range_lower
->get_locus (),
10307 "token type %qs cannot be parsed as range pattern bound",
10308 range_lower
->get_token_description ()));
10313 const_TokenPtr next
= lexer
.peek_token ();
10314 if (next
->get_id () == DOT_DOT_EQ
|| next
->get_id () == ELLIPSIS
)
10317 lexer
.skip_token ();
10318 std::unique_ptr
<AST::RangePatternBound
> lower (
10319 new AST::RangePatternBoundLiteral (
10320 AST::Literal (range_lower
->get_str (), type
,
10321 PrimitiveCoreType::CORETYPE_UNKNOWN
),
10322 range_lower
->get_locus (), has_minus
));
10324 std::unique_ptr
<AST::RangePatternBound
> upper
10325 = parse_range_pattern_bound ();
10326 if (upper
== nullptr)
10328 Error
error (next
->get_locus (),
10329 "failed to parse range pattern bound in range pattern");
10330 add_error (std::move (error
));
10335 return std::unique_ptr
<AST::RangePattern
> (
10336 new AST::RangePattern (std::move (lower
), std::move (upper
),
10337 range_lower
->get_locus ()));
10342 return std::unique_ptr
<AST::LiteralPattern
> (
10343 new AST::LiteralPattern (range_lower
->get_str (), type
,
10344 range_lower
->get_locus ()));
10348 // Parses a range pattern bound (value only).
10349 template <typename ManagedTokenSource
>
10350 std::unique_ptr
<AST::RangePatternBound
>
10351 Parser
<ManagedTokenSource
>::parse_range_pattern_bound ()
10353 const_TokenPtr range_lower
= lexer
.peek_token ();
10354 Location range_lower_locus
= range_lower
->get_locus ();
10357 switch (range_lower
->get_id ())
10360 lexer
.skip_token ();
10361 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10362 new AST::RangePatternBoundLiteral (
10363 AST::Literal (range_lower
->get_str (), AST::Literal::CHAR
,
10364 range_lower
->get_type_hint ()),
10365 range_lower_locus
));
10366 case BYTE_CHAR_LITERAL
:
10367 lexer
.skip_token ();
10368 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10369 new AST::RangePatternBoundLiteral (
10370 AST::Literal (range_lower
->get_str (), AST::Literal::BYTE
,
10371 range_lower
->get_type_hint ()),
10372 range_lower_locus
));
10374 lexer
.skip_token ();
10375 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10376 new AST::RangePatternBoundLiteral (
10377 AST::Literal (range_lower
->get_str (), AST::Literal::INT
,
10378 range_lower
->get_type_hint ()),
10379 range_lower_locus
));
10380 case FLOAT_LITERAL
:
10381 lexer
.skip_token ();
10382 rust_debug ("warning: used deprecated float range pattern bound");
10383 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10384 new AST::RangePatternBoundLiteral (
10385 AST::Literal (range_lower
->get_str (), AST::Literal::FLOAT
,
10386 range_lower
->get_type_hint ()),
10387 range_lower_locus
));
10389 // branch on next token
10390 range_lower
= lexer
.peek_token (1);
10391 switch (range_lower
->get_id ())
10394 lexer
.skip_token (1);
10395 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10396 new AST::RangePatternBoundLiteral (
10397 AST::Literal (range_lower
->get_str (), AST::Literal::INT
,
10398 range_lower
->get_type_hint ()),
10399 range_lower_locus
, true));
10400 case FLOAT_LITERAL
:
10401 lexer
.skip_token (1);
10402 rust_debug ("warning: used deprecated float range pattern bound");
10403 return std::unique_ptr
<AST::RangePatternBoundLiteral
> (
10404 new AST::RangePatternBoundLiteral (
10405 AST::Literal (range_lower
->get_str (), AST::Literal::FLOAT
,
10406 range_lower
->get_type_hint ()),
10407 range_lower_locus
, true));
10409 add_error (Error (range_lower
->get_locus (),
10410 "token type %qs cannot be parsed as range pattern "
10411 "bound after minus symbol",
10412 range_lower
->get_token_description ()));
10421 case SCOPE_RESOLUTION
:
10422 case DOLLAR_SIGN
: {
10423 // path in expression
10424 AST::PathInExpression path
= parse_path_in_expression ();
10425 if (path
.is_error ())
10428 range_lower
->get_locus (),
10429 "failed to parse path in expression range pattern bound");
10430 add_error (std::move (error
));
10434 return std::unique_ptr
<AST::RangePatternBoundPath
> (
10435 new AST::RangePatternBoundPath (std::move (path
)));
10438 // qualified path in expression
10439 AST::QualifiedPathInExpression path
10440 = parse_qualified_path_in_expression ();
10441 if (path
.is_error ())
10443 Error
error (range_lower
->get_locus (),
10444 "failed to parse qualified path in expression range "
10446 add_error (std::move (error
));
10450 return std::unique_ptr
<AST::RangePatternBoundQualPath
> (
10451 new AST::RangePatternBoundQualPath (std::move (path
)));
10455 Error (range_lower
->get_locus (),
10456 "token type %qs cannot be parsed as range pattern bound",
10457 range_lower
->get_token_description ()));
10463 // Parses a pattern (will further disambiguate any pattern).
10464 template <typename ManagedTokenSource
>
10465 std::unique_ptr
<AST::Pattern
>
10466 Parser
<ManagedTokenSource
>::parse_pattern ()
10468 const_TokenPtr t
= lexer
.peek_token ();
10469 switch (t
->get_id ())
10472 lexer
.skip_token ();
10473 return std::unique_ptr
<AST::LiteralPattern
> (
10474 new AST::LiteralPattern ("true", AST::Literal::BOOL
, t
->get_locus ()));
10475 case FALSE_LITERAL
:
10476 lexer
.skip_token ();
10477 return std::unique_ptr
<AST::LiteralPattern
> (
10478 new AST::LiteralPattern ("false", AST::Literal::BOOL
, t
->get_locus ()));
10480 case BYTE_CHAR_LITERAL
:
10482 case FLOAT_LITERAL
:
10483 return parse_literal_or_range_pattern ();
10484 case STRING_LITERAL
:
10485 lexer
.skip_token ();
10486 return std::unique_ptr
<AST::LiteralPattern
> (
10487 new AST::LiteralPattern (t
->get_str (), AST::Literal::STRING
,
10489 case BYTE_STRING_LITERAL
:
10490 lexer
.skip_token ();
10491 return std::unique_ptr
<AST::LiteralPattern
> (
10492 new AST::LiteralPattern (t
->get_str (), AST::Literal::BYTE_STRING
,
10494 // raw string and raw byte string literals too if they are readded to
10497 if (lexer
.peek_token (1)->get_id () == INT_LITERAL
)
10499 return parse_literal_or_range_pattern ();
10501 else if (lexer
.peek_token (1)->get_id () == FLOAT_LITERAL
)
10503 return parse_literal_or_range_pattern ();
10507 Error
error (t
->get_locus (), "unexpected token %<-%> in pattern - "
10508 "did you forget an integer literal");
10509 add_error (std::move (error
));
10514 lexer
.skip_token ();
10515 return std::unique_ptr
<AST::WildcardPattern
> (
10516 new AST::WildcardPattern (t
->get_locus ()));
10519 return parse_identifier_pattern ();
10521 /* if identifier with no scope resolution afterwards, identifier
10522 * pattern. if scope resolution afterwards, path pattern (or range
10523 * pattern or struct pattern or tuple struct pattern) or macro
10525 return parse_ident_leading_pattern ();
10528 // reference pattern
10529 return parse_reference_pattern ();
10531 // tuple pattern or grouped pattern
10532 return parse_grouped_or_tuple_pattern ();
10535 return parse_slice_pattern ();
10537 // qualified path in expression or qualified range pattern bound
10538 AST::QualifiedPathInExpression path
10539 = parse_qualified_path_in_expression ();
10541 if (lexer
.peek_token ()->get_id () == DOT_DOT_EQ
10542 || lexer
.peek_token ()->get_id () == ELLIPSIS
)
10544 // qualified range pattern bound, so parse rest of range pattern
10545 bool has_ellipsis_syntax
10546 = lexer
.peek_token ()->get_id () == ELLIPSIS
;
10547 lexer
.skip_token ();
10549 std::unique_ptr
<AST::RangePatternBoundQualPath
> lower_bound (
10550 new AST::RangePatternBoundQualPath (std::move (path
)));
10551 std::unique_ptr
<AST::RangePatternBound
> upper_bound
10552 = parse_range_pattern_bound ();
10554 return std::unique_ptr
<AST::RangePattern
> (
10555 new AST::RangePattern (std::move (lower_bound
),
10556 std::move (upper_bound
), t
->get_locus (),
10557 has_ellipsis_syntax
));
10561 // just qualified path in expression
10562 return std::unique_ptr
<AST::QualifiedPathInExpression
> (
10563 new AST::QualifiedPathInExpression (std::move (path
)));
10570 case SCOPE_RESOLUTION
:
10571 case DOLLAR_SIGN
: {
10572 // path in expression or range pattern bound
10573 AST::PathInExpression path
= parse_path_in_expression ();
10575 const_TokenPtr next
= lexer
.peek_token ();
10576 switch (next
->get_id ())
10580 // qualified range pattern bound, so parse rest of range pattern
10581 bool has_ellipsis_syntax
10582 = lexer
.peek_token ()->get_id () == ELLIPSIS
;
10583 lexer
.skip_token ();
10585 std::unique_ptr
<AST::RangePatternBoundPath
> lower_bound (
10586 new AST::RangePatternBoundPath (std::move (path
)));
10587 std::unique_ptr
<AST::RangePatternBound
> upper_bound
10588 = parse_range_pattern_bound ();
10590 return std::unique_ptr
<AST::RangePattern
> (new AST::RangePattern (
10591 std::move (lower_bound
), std::move (upper_bound
),
10592 Linemap::unknown_location (), has_ellipsis_syntax
));
10595 return parse_macro_invocation_partial (std::move (path
),
10599 lexer
.skip_token ();
10601 // check if empty tuple
10602 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
10604 lexer
.skip_token ();
10605 return std::unique_ptr
<AST::TupleStructPattern
> (
10606 new AST::TupleStructPattern (std::move (path
), nullptr));
10610 std::unique_ptr
<AST::TupleStructItems
> items
10611 = parse_tuple_struct_items ();
10612 if (items
== nullptr)
10614 Error
error (lexer
.peek_token ()->get_locus (),
10615 "failed to parse tuple struct items");
10616 add_error (std::move (error
));
10621 if (!skip_token (RIGHT_PAREN
))
10626 return std::unique_ptr
<AST::TupleStructPattern
> (
10627 new AST::TupleStructPattern (std::move (path
),
10628 std::move (items
)));
10632 lexer
.skip_token ();
10634 // parse elements (optional)
10635 AST::StructPatternElements elems
= parse_struct_pattern_elems ();
10637 if (!skip_token (RIGHT_CURLY
))
10642 return std::unique_ptr
<AST::StructPattern
> (
10643 new AST::StructPattern (std::move (path
), t
->get_locus (),
10644 std::move (elems
)));
10647 // assume path in expression
10648 return std::unique_ptr
<AST::PathInExpression
> (
10649 new AST::PathInExpression (std::move (path
)));
10653 add_error (Error (t
->get_locus (), "unexpected token %qs in pattern",
10654 t
->get_token_description ()));
10660 // Parses a single or double reference pattern.
10661 template <typename ManagedTokenSource
>
10662 std::unique_ptr
<AST::ReferencePattern
>
10663 Parser
<ManagedTokenSource
>::parse_reference_pattern ()
10665 // parse double or single ref
10666 bool is_double_ref
= false;
10667 const_TokenPtr t
= lexer
.peek_token ();
10668 switch (t
->get_id ())
10672 lexer
.skip_token ();
10675 is_double_ref
= true;
10676 lexer
.skip_token ();
10679 add_error (Error (t
->get_locus (),
10680 "unexpected token %qs in reference pattern",
10681 t
->get_token_description ()));
10686 // parse mut (if it exists)
10687 bool is_mut
= false;
10688 if (lexer
.peek_token ()->get_id () == MUT
)
10691 lexer
.skip_token ();
10694 // parse pattern to get reference of (required)
10695 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
10696 if (pattern
== nullptr)
10698 Error
error (lexer
.peek_token ()->get_locus (),
10699 "failed to parse pattern in reference pattern");
10700 add_error (std::move (error
));
10706 return std::unique_ptr
<AST::ReferencePattern
> (
10707 new AST::ReferencePattern (std::move (pattern
), is_mut
, is_double_ref
,
10711 /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if
10712 * only a single element with no commas. */
10713 template <typename ManagedTokenSource
>
10714 std::unique_ptr
<AST::Pattern
>
10715 Parser
<ManagedTokenSource
>::parse_grouped_or_tuple_pattern ()
10717 Location paren_locus
= lexer
.peek_token ()->get_locus ();
10718 skip_token (LEFT_PAREN
);
10720 // detect '..' token (ranged with no lower range)
10721 if (lexer
.peek_token ()->get_id () == DOT_DOT
)
10723 lexer
.skip_token ();
10725 // parse new patterns while next token is a comma
10726 std::vector
<std::unique_ptr
<AST::Pattern
>> patterns
;
10728 const_TokenPtr t
= lexer
.peek_token ();
10729 while (t
->get_id () == COMMA
)
10731 lexer
.skip_token ();
10733 // break if next token is ')'
10734 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
10739 // parse pattern, which is required
10740 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
10741 if (pattern
== nullptr)
10744 lexer
.peek_token ()->get_locus (),
10745 "failed to parse pattern inside ranged tuple pattern");
10746 add_error (std::move (error
));
10751 patterns
.push_back (std::move (pattern
));
10753 t
= lexer
.peek_token ();
10756 if (!skip_token (RIGHT_PAREN
))
10762 // create ranged tuple pattern items with only upper items
10763 std::unique_ptr
<AST::TuplePatternItemsRanged
> items (
10764 new AST::TuplePatternItemsRanged (
10765 std::vector
<std::unique_ptr
<AST::Pattern
>> (), std::move (patterns
)));
10766 return std::unique_ptr
<AST::TuplePattern
> (
10767 new AST::TuplePattern (std::move (items
), paren_locus
));
10770 // parse initial pattern (required)
10771 std::unique_ptr
<AST::Pattern
> initial_pattern
= parse_pattern ();
10772 if (initial_pattern
== nullptr)
10774 Error
error (lexer
.peek_token ()->get_locus (),
10775 "failed to parse pattern in grouped or tuple pattern");
10776 add_error (std::move (error
));
10781 // branch on whether next token is a comma or not
10782 const_TokenPtr t
= lexer
.peek_token ();
10783 switch (t
->get_id ())
10787 lexer
.skip_token ();
10789 return std::unique_ptr
<AST::GroupedPattern
> (
10790 new AST::GroupedPattern (std::move (initial_pattern
), paren_locus
));
10793 lexer
.skip_token ();
10795 // create vector of patterns
10796 std::vector
<std::unique_ptr
<AST::Pattern
>> patterns
;
10797 patterns
.push_back (std::move (initial_pattern
));
10799 t
= lexer
.peek_token ();
10800 while (t
->get_id () != RIGHT_PAREN
&& t
->get_id () != DOT_DOT
)
10802 // parse pattern (required)
10803 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
10804 if (pattern
== nullptr)
10806 Error
error (t
->get_locus (),
10807 "failed to parse pattern in tuple pattern");
10808 add_error (std::move (error
));
10812 patterns
.push_back (std::move (pattern
));
10814 if (lexer
.peek_token ()->get_id () != COMMA
)
10817 lexer
.skip_token ();
10818 t
= lexer
.peek_token ();
10821 t
= lexer
.peek_token ();
10822 if (t
->get_id () == RIGHT_PAREN
)
10824 // non-ranged tuple pattern
10825 lexer
.skip_token ();
10827 std::unique_ptr
<AST::TuplePatternItemsMultiple
> items (
10828 new AST::TuplePatternItemsMultiple (std::move (patterns
)));
10829 return std::unique_ptr
<AST::TuplePattern
> (
10830 new AST::TuplePattern (std::move (items
), paren_locus
));
10832 else if (t
->get_id () == DOT_DOT
)
10834 // ranged tuple pattern
10835 lexer
.skip_token ();
10837 // parse upper patterns
10838 std::vector
<std::unique_ptr
<AST::Pattern
>> upper_patterns
;
10839 t
= lexer
.peek_token ();
10840 while (t
->get_id () == COMMA
)
10842 lexer
.skip_token ();
10845 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
10848 // parse pattern (required)
10849 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
10850 if (pattern
== nullptr)
10852 Error
error (lexer
.peek_token ()->get_locus (),
10853 "failed to parse pattern in tuple pattern");
10854 add_error (std::move (error
));
10858 upper_patterns
.push_back (std::move (pattern
));
10860 t
= lexer
.peek_token ();
10863 if (!skip_token (RIGHT_PAREN
))
10868 std::unique_ptr
<AST::TuplePatternItemsRanged
> items (
10869 new AST::TuplePatternItemsRanged (std::move (patterns
),
10870 std::move (upper_patterns
)));
10871 return std::unique_ptr
<AST::TuplePattern
> (
10872 new AST::TuplePattern (std::move (items
), paren_locus
));
10876 // some kind of error
10877 Error
error (t
->get_locus (),
10878 "failed to parse tuple pattern (probably) or maybe "
10879 "grouped pattern");
10880 add_error (std::move (error
));
10887 add_error (Error (t
->get_locus (),
10888 "unrecognised token %qs in grouped or tuple pattern "
10889 "after first pattern",
10890 t
->get_token_description ()));
10896 /* Parses a slice pattern that can match arrays or slices. Parses the square
10898 template <typename ManagedTokenSource
>
10899 std::unique_ptr
<AST::SlicePattern
>
10900 Parser
<ManagedTokenSource
>::parse_slice_pattern ()
10902 Location square_locus
= lexer
.peek_token ()->get_locus ();
10903 skip_token (LEFT_SQUARE
);
10905 // parse initial pattern (required)
10906 std::unique_ptr
<AST::Pattern
> initial_pattern
= parse_pattern ();
10907 if (initial_pattern
== nullptr)
10909 Error
error (lexer
.peek_token ()->get_locus (),
10910 "failed to parse initial pattern in slice pattern");
10911 add_error (std::move (error
));
10916 std::vector
<std::unique_ptr
<AST::Pattern
>> patterns
;
10917 patterns
.push_back (std::move (initial_pattern
));
10919 const_TokenPtr t
= lexer
.peek_token ();
10920 while (t
->get_id () == COMMA
)
10922 lexer
.skip_token ();
10924 // break if end bracket
10925 if (lexer
.peek_token ()->get_id () == RIGHT_SQUARE
)
10928 // parse pattern (required)
10929 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
10930 if (pattern
== nullptr)
10932 Error
error (lexer
.peek_token ()->get_locus (),
10933 "failed to parse pattern in slice pattern");
10934 add_error (std::move (error
));
10938 patterns
.push_back (std::move (pattern
));
10940 t
= lexer
.peek_token ();
10943 if (!skip_token (RIGHT_SQUARE
))
10948 return std::unique_ptr
<AST::SlicePattern
> (
10949 new AST::SlicePattern (std::move (patterns
), square_locus
));
10952 /* Parses an identifier pattern (pattern that binds a value matched to a
10954 template <typename ManagedTokenSource
>
10955 std::unique_ptr
<AST::IdentifierPattern
>
10956 Parser
<ManagedTokenSource
>::parse_identifier_pattern ()
10958 Location locus
= lexer
.peek_token ()->get_locus ();
10960 bool has_ref
= false;
10961 if (lexer
.peek_token ()->get_id () == REF
)
10964 lexer
.skip_token ();
10967 rust_debug ("parsed ref in identifier pattern");
10970 bool has_mut
= false;
10971 if (lexer
.peek_token ()->get_id () == MUT
)
10974 lexer
.skip_token ();
10977 // parse identifier (required)
10978 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
10979 if (ident_tok
== nullptr)
10984 Identifier ident
= ident_tok
->get_str ();
10987 rust_debug ("parsed identifier in identifier pattern");
10989 // parse optional pattern binding thing
10990 std::unique_ptr
<AST::Pattern
> bind_pattern
= nullptr;
10991 if (lexer
.peek_token ()->get_id () == PATTERN_BIND
)
10993 lexer
.skip_token ();
10995 // parse required pattern to bind
10996 bind_pattern
= parse_pattern ();
10997 if (bind_pattern
== nullptr)
10999 Error
error (lexer
.peek_token ()->get_locus (),
11000 "failed to parse pattern to bind in identifier pattern");
11001 add_error (std::move (error
));
11008 rust_debug ("about to return identifier pattern");
11010 return std::unique_ptr
<AST::IdentifierPattern
> (
11011 new AST::IdentifierPattern (std::move (ident
), locus
, has_ref
, has_mut
,
11012 std::move (bind_pattern
)));
11015 /* Parses a pattern that opens with an identifier. This includes identifier
11016 * patterns, path patterns (and derivatives such as struct patterns, tuple
11017 * struct patterns, and macro invocations), and ranges. */
11018 template <typename ManagedTokenSource
>
11019 std::unique_ptr
<AST::Pattern
>
11020 Parser
<ManagedTokenSource
>::parse_ident_leading_pattern ()
11022 // ensure first token is actually identifier
11023 const_TokenPtr initial_tok
= lexer
.peek_token ();
11024 if (initial_tok
->get_id () != IDENTIFIER
)
11029 // save initial identifier as it may be useful (but don't skip)
11030 std::string initial_ident
= initial_tok
->get_str ();
11032 // parse next tokens as a PathInExpression
11033 AST::PathInExpression path
= parse_path_in_expression ();
11035 // branch on next token
11036 const_TokenPtr t
= lexer
.peek_token ();
11037 switch (t
->get_id ())
11040 return parse_macro_invocation_partial (std::move (path
), AST::AttrVec ());
11043 lexer
.skip_token ();
11046 rust_debug ("parsing tuple struct pattern");
11048 // check if empty tuple
11049 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
11051 lexer
.skip_token ();
11052 return std::unique_ptr
<AST::TupleStructPattern
> (
11053 new AST::TupleStructPattern (std::move (path
), nullptr));
11057 std::unique_ptr
<AST::TupleStructItems
> items
11058 = parse_tuple_struct_items ();
11059 if (items
== nullptr)
11061 Error
error (lexer
.peek_token ()->get_locus (),
11062 "failed to parse tuple struct items");
11063 add_error (std::move (error
));
11069 rust_debug ("successfully parsed tuple struct items");
11071 if (!skip_token (RIGHT_PAREN
))
11077 rust_debug ("successfully parsed tuple struct pattern");
11079 return std::unique_ptr
<AST::TupleStructPattern
> (
11080 new AST::TupleStructPattern (std::move (path
), std::move (items
)));
11084 lexer
.skip_token ();
11086 // parse elements (optional)
11087 AST::StructPatternElements elems
= parse_struct_pattern_elems ();
11089 if (!skip_token (RIGHT_CURLY
))
11095 rust_debug ("successfully parsed struct pattern");
11097 return std::unique_ptr
<AST::StructPattern
> (
11098 new AST::StructPattern (std::move (path
), initial_tok
->get_locus (),
11099 std::move (elems
)));
11104 bool has_ellipsis_syntax
= lexer
.peek_token ()->get_id () == ELLIPSIS
;
11106 lexer
.skip_token ();
11108 std::unique_ptr
<AST::RangePatternBoundPath
> lower_bound (
11109 new AST::RangePatternBoundPath (std::move (path
)));
11110 std::unique_ptr
<AST::RangePatternBound
> upper_bound
11111 = parse_range_pattern_bound ();
11113 return std::unique_ptr
<AST::RangePattern
> (new AST::RangePattern (
11114 std::move (lower_bound
), std::move (upper_bound
),
11115 Linemap::unknown_location (), has_ellipsis_syntax
));
11117 case PATTERN_BIND
: {
11118 // only allow on single-segment paths
11119 if (path
.is_single_segment ())
11121 // identifier with pattern bind
11122 lexer
.skip_token ();
11124 std::unique_ptr
<AST::Pattern
> bind_pattern
= parse_pattern ();
11125 if (bind_pattern
== nullptr)
11129 "failed to parse pattern to bind to identifier pattern");
11130 add_error (std::move (error
));
11134 return std::unique_ptr
<AST::IdentifierPattern
> (
11135 new AST::IdentifierPattern (std::move (initial_ident
),
11136 initial_tok
->get_locus (), false,
11137 false, std::move (bind_pattern
)));
11141 "failed to parse pattern bind to a path, not an identifier");
11142 add_error (std::move (error
));
11147 // assume identifier if single segment
11148 if (path
.is_single_segment ())
11150 return std::unique_ptr
<AST::IdentifierPattern
> (
11151 new AST::IdentifierPattern (std::move (initial_ident
),
11152 initial_tok
->get_locus ()));
11154 // return path otherwise
11155 return std::unique_ptr
<AST::PathInExpression
> (
11156 new AST::PathInExpression (std::move (path
)));
11160 // Parses tuple struct items if they exist. Does not parse parentheses.
11161 template <typename ManagedTokenSource
>
11162 std::unique_ptr
<AST::TupleStructItems
>
11163 Parser
<ManagedTokenSource
>::parse_tuple_struct_items ()
11165 std::vector
<std::unique_ptr
<AST::Pattern
>> lower_patterns
;
11168 rust_debug ("started parsing tuple struct items");
11170 // check for '..' at front
11171 if (lexer
.peek_token ()->get_id () == DOT_DOT
)
11173 // only parse upper patterns
11174 lexer
.skip_token ();
11177 rust_debug ("'..' at front in tuple struct items detected");
11179 std::vector
<std::unique_ptr
<AST::Pattern
>> upper_patterns
;
11181 const_TokenPtr t
= lexer
.peek_token ();
11182 while (t
->get_id () == COMMA
)
11184 lexer
.skip_token ();
11186 // break if right paren
11187 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
11190 // parse pattern, which is now required
11191 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
11192 if (pattern
== nullptr)
11194 Error
error (lexer
.peek_token ()->get_locus (),
11195 "failed to parse pattern in tuple struct items");
11196 add_error (std::move (error
));
11200 upper_patterns
.push_back (std::move (pattern
));
11202 t
= lexer
.peek_token ();
11207 "finished parsing tuple struct items ranged (upper/none only)");
11209 return std::unique_ptr
<AST::TupleStructItemsRange
> (
11210 new AST::TupleStructItemsRange (std::move (lower_patterns
),
11211 std::move (upper_patterns
)));
11214 // has at least some lower patterns
11215 const_TokenPtr t
= lexer
.peek_token ();
11216 while (t
->get_id () != RIGHT_PAREN
&& t
->get_id () != DOT_DOT
)
11219 rust_debug ("about to parse pattern in tuple struct items");
11221 // parse pattern, which is required
11222 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
11223 if (pattern
== nullptr)
11225 Error
error (t
->get_locus (),
11226 "failed to parse pattern in tuple struct items");
11227 add_error (std::move (error
));
11231 lower_patterns
.push_back (std::move (pattern
));
11234 rust_debug ("successfully parsed pattern in tuple struct items");
11236 if (lexer
.peek_token ()->get_id () != COMMA
)
11239 rust_debug ("broke out of parsing patterns in tuple struct "
11240 "items as no comma");
11244 lexer
.skip_token ();
11245 t
= lexer
.peek_token ();
11248 // branch on next token
11249 t
= lexer
.peek_token ();
11250 switch (t
->get_id ())
11253 return std::unique_ptr
<AST::TupleStructItemsNoRange
> (
11254 new AST::TupleStructItemsNoRange (std::move (lower_patterns
)));
11256 // has an upper range that must be parsed separately
11257 lexer
.skip_token ();
11259 std::vector
<std::unique_ptr
<AST::Pattern
>> upper_patterns
;
11261 t
= lexer
.peek_token ();
11262 while (t
->get_id () == COMMA
)
11264 lexer
.skip_token ();
11266 // break if next token is right paren
11267 if (lexer
.peek_token ()->get_id () == RIGHT_PAREN
)
11270 // parse pattern, which is required
11271 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
11272 if (pattern
== nullptr)
11274 Error
error (lexer
.peek_token ()->get_locus (),
11275 "failed to parse pattern in tuple struct items");
11276 add_error (std::move (error
));
11280 upper_patterns
.push_back (std::move (pattern
));
11282 t
= lexer
.peek_token ();
11285 return std::unique_ptr
<AST::TupleStructItemsRange
> (
11286 new AST::TupleStructItemsRange (std::move (lower_patterns
),
11287 std::move (upper_patterns
)));
11291 add_error (Error (t
->get_locus (),
11292 "unexpected token %qs in tuple struct items",
11293 t
->get_token_description ()));
11299 // Parses struct pattern elements if they exist.
11300 template <typename ManagedTokenSource
>
11301 AST::StructPatternElements
11302 Parser
<ManagedTokenSource
>::parse_struct_pattern_elems ()
11304 std::vector
<std::unique_ptr
<AST::StructPatternField
>> fields
;
11306 AST::AttrVec etc_attrs
;
11307 bool has_etc
= false;
11309 // try parsing struct pattern fields
11310 const_TokenPtr t
= lexer
.peek_token ();
11311 while (t
->get_id () != RIGHT_CURLY
)
11313 AST::AttrVec outer_attrs
= parse_outer_attributes ();
11315 // parse etc (must be last in struct pattern, so breaks)
11316 if (lexer
.peek_token ()->get_id () == DOT_DOT
)
11318 lexer
.skip_token ();
11319 etc_attrs
= std::move (outer_attrs
);
11324 std::unique_ptr
<AST::StructPatternField
> field
11325 = parse_struct_pattern_field_partial (std::move (outer_attrs
));
11326 if (field
== nullptr)
11328 Error
error (lexer
.peek_token ()->get_locus (),
11329 "failed to parse struct pattern field");
11330 add_error (std::move (error
));
11332 // skip after somewhere?
11333 return AST::StructPatternElements::create_empty ();
11335 fields
.push_back (std::move (field
));
11337 if (lexer
.peek_token ()->get_id () != COMMA
)
11341 lexer
.skip_token ();
11342 t
= lexer
.peek_token ();
11346 return AST::StructPatternElements (std::move (fields
),
11347 std::move (etc_attrs
));
11349 return AST::StructPatternElements (std::move (fields
));
11352 /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
11354 template <typename ManagedTokenSource
>
11355 std::unique_ptr
<AST::StructPatternField
>
11356 Parser
<ManagedTokenSource
>::parse_struct_pattern_field ()
11358 // parse outer attributes (if they exist)
11359 AST::AttrVec outer_attrs
= parse_outer_attributes ();
11361 return parse_struct_pattern_field_partial (std::move (outer_attrs
));
11364 /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
11365 * identifier), with outer attributes passed in. */
11366 template <typename ManagedTokenSource
>
11367 std::unique_ptr
<AST::StructPatternField
>
11368 Parser
<ManagedTokenSource
>::parse_struct_pattern_field_partial (
11369 AST::AttrVec outer_attrs
)
11371 // branch based on next token
11372 const_TokenPtr t
= lexer
.peek_token ();
11373 switch (t
->get_id ())
11375 case INT_LITERAL
: {
11377 std::string index_str
= t
->get_str ();
11378 int index
= atoi (index_str
.c_str ());
11380 if (!skip_token (COLON
))
11385 // parse required pattern
11386 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
11387 if (pattern
== nullptr)
11391 "failed to parse pattern in tuple index struct pattern field");
11392 add_error (std::move (error
));
11397 return std::unique_ptr
<AST::StructPatternFieldTuplePat
> (
11398 new AST::StructPatternFieldTuplePat (index
, std::move (pattern
),
11399 std::move (outer_attrs
),
11403 // identifier-pattern OR only identifier
11404 // branch on next token
11405 switch (lexer
.peek_token (1)->get_id ())
11408 // identifier-pattern
11409 Identifier ident
= t
->get_str ();
11410 lexer
.skip_token ();
11412 skip_token (COLON
);
11414 // parse required pattern
11415 std::unique_ptr
<AST::Pattern
> pattern
= parse_pattern ();
11416 if (pattern
== nullptr)
11418 Error
error (t
->get_locus (),
11419 "failed to parse pattern in struct pattern field");
11420 add_error (std::move (error
));
11425 return std::unique_ptr
<AST::StructPatternFieldIdentPat
> (
11426 new AST::StructPatternFieldIdentPat (std::move (ident
),
11427 std::move (pattern
),
11428 std::move (outer_attrs
),
11432 case RIGHT_CURLY
: {
11434 Identifier ident
= t
->get_str ();
11435 lexer
.skip_token ();
11437 return std::unique_ptr
<AST::StructPatternFieldIdent
> (
11438 new AST::StructPatternFieldIdent (std::move (ident
), false, false,
11439 std::move (outer_attrs
),
11444 add_error (Error (t
->get_locus (),
11445 "unrecognised token %qs in struct pattern field",
11446 t
->get_token_description ()));
11453 bool has_ref
= false;
11454 if (t
->get_id () == REF
)
11457 lexer
.skip_token ();
11460 bool has_mut
= false;
11461 if (lexer
.peek_token ()->get_id () == MUT
)
11464 lexer
.skip_token ();
11467 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
11468 if (ident_tok
== nullptr)
11472 Identifier ident
= ident_tok
->get_str ();
11474 return std::unique_ptr
<AST::StructPatternFieldIdent
> (
11475 new AST::StructPatternFieldIdent (std::move (ident
), has_ref
, has_mut
,
11476 std::move (outer_attrs
),
11480 // not necessarily an error
11485 template <typename ManagedTokenSource
>
11487 Parser
<ManagedTokenSource
>::parse_stmt_or_expr_with_block (
11488 AST::AttrVec outer_attrs
)
11490 auto expr
= parse_expr_with_block (std::move (outer_attrs
));
11491 if (expr
== nullptr)
11492 return ExprOrStmt::create_error ();
11494 auto tok
= lexer
.peek_token ();
11496 // tail expr in a block expr
11497 if (tok
->get_id () == RIGHT_CURLY
)
11498 return ExprOrStmt (std::move (expr
));
11500 // internal block expr must either have semicolons followed, or evaluate to
11502 auto locus
= expr
->get_locus ();
11503 std::unique_ptr
<AST::ExprStmtWithBlock
> stmt (
11504 new AST::ExprStmtWithBlock (std::move (expr
), locus
,
11505 tok
->get_id () == SEMICOLON
));
11506 if (tok
->get_id () == SEMICOLON
)
11507 lexer
.skip_token ();
11509 return ExprOrStmt (std::move (stmt
));
11512 /* Parses a statement or expression (depending on whether a trailing semicolon
11513 * exists). Useful for block expressions where it cannot be determined through
11514 * lookahead whether it is a statement or expression to be parsed. */
11515 template <typename ManagedTokenSource
>
11517 Parser
<ManagedTokenSource
>::parse_stmt_or_expr_without_block ()
11519 // quick exit for empty statement
11520 const_TokenPtr t
= lexer
.peek_token ();
11521 if (t
->get_id () == SEMICOLON
)
11523 lexer
.skip_token ();
11524 std::unique_ptr
<AST::EmptyStmt
> stmt (
11525 new AST::EmptyStmt (t
->get_locus ()));
11526 return ExprOrStmt (std::move (stmt
));
11529 // parse outer attributes
11530 AST::AttrVec outer_attrs
= parse_outer_attributes ();
11532 // parsing this will be annoying because of the many different possibilities
11533 /* best may be just to copy paste in parse_item switch, and failing that try
11534 * to parse outer attributes, and then pass them in to either a let
11535 * statement or (fallback) expression statement. */
11536 // FIXME: think of a way to do this without such a large switch?
11538 /* FIXME: for expressions at least, the only way that they can really be
11539 * parsed properly in this way is if they don't support operators on them.
11540 * They must be pratt-parsed otherwise. As such due to composability, only
11541 * explicit statements will have special cases here. This should roughly
11542 * correspond to "expr-with-block", but this warning is here in case it
11543 * isn't the case. */
11544 t
= lexer
.peek_token ();
11545 switch (t
->get_id ())
11549 std::unique_ptr
<AST::LetStmt
> stmt (
11550 parse_let_stmt (std::move (outer_attrs
)));
11551 return ExprOrStmt (std::move (stmt
));
11565 std::unique_ptr
<AST::VisItem
> item (
11566 parse_vis_item (std::move (outer_attrs
)));
11567 return ExprOrStmt (std::move (item
));
11569 /* TODO: implement union keyword but not really because of
11570 * context-dependence crappy hack way to parse a union written below to
11571 * separate it from the good code. */
11573 case UNSAFE
: { // maybe - unsafe traits are a thing
11574 /* if any of these (should be all possible VisItem prefixes), parse a
11575 * VisItem - can't parse item because would require reparsing outer
11577 const_TokenPtr t2
= lexer
.peek_token (1);
11578 switch (t2
->get_id ())
11582 return parse_stmt_or_expr_with_block (std::move (outer_attrs
));
11586 std::unique_ptr
<AST::VisItem
> item (
11587 parse_vis_item (std::move (outer_attrs
)));
11588 return ExprOrStmt (std::move (item
));
11593 std::unique_ptr
<AST::VisItem
> item (
11594 parse_vis_item (std::move (outer_attrs
)));
11595 return ExprOrStmt (std::move (item
));
11598 // unsafe trait impl
11599 std::unique_ptr
<AST::VisItem
> item (
11600 parse_vis_item (std::move (outer_attrs
)));
11601 return ExprOrStmt (std::move (item
));
11604 add_error (Error (t2
->get_locus (),
11605 "unrecognised token %qs after parsing unsafe - "
11606 "expected beginning of expression or statement",
11607 t
->get_token_description ()));
11610 return ExprOrStmt::create_error ();
11616 case DOLLAR_SIGN
: {
11617 /* path-based thing so struct/enum or path or macro invocation of a
11618 * kind. however, the expressions are composable (i think) */
11620 std::unique_ptr
<AST::ExprWithoutBlock
> expr
11621 = parse_expr_without_block ();
11623 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
11625 // must be expression statement
11626 lexer
.skip_token ();
11628 std::unique_ptr
<AST::ExprStmtWithoutBlock
> stmt (
11629 new AST::ExprStmtWithoutBlock (std::move (expr
),
11631 return ExprOrStmt (std::move (stmt
));
11634 // return expression
11635 return ExprOrStmt (std::move (expr
));
11637 /* FIXME: this is either a macro invocation or macro invocation semi.
11638 * start parsing to determine which one it is. */
11639 // FIXME: or this is another path-based thing - struct/enum or path
11640 // itself return parse_path_based_stmt_or_expr(std::move(outer_attrs));
11641 // FIXME: old code there
11649 return parse_stmt_or_expr_with_block (std::move (outer_attrs
));
11652 /* FIXME: are there any expressions without blocks that can have
11653 * lifetime as their first token? Or is loop expr the only one? */
11654 // safe side for now:
11655 const_TokenPtr t2
= lexer
.peek_token (2);
11656 if (lexer
.peek_token (1)->get_id () == COLON
11657 && (t2
->get_id () == LOOP
|| t2
->get_id () == WHILE
11658 || t2
->get_id () == FOR
))
11660 return parse_stmt_or_expr_with_block (std::move (outer_attrs
));
11664 // should be expr without block
11665 std::unique_ptr
<AST::ExprWithoutBlock
> expr
11666 = parse_expr_without_block (std::move (outer_attrs
));
11668 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
11670 // must be expression statement
11671 lexer
.skip_token ();
11673 std::unique_ptr
<AST::ExprStmtWithoutBlock
> stmt (
11674 new AST::ExprStmtWithoutBlock (std::move (expr
),
11676 return ExprOrStmt (std::move (stmt
));
11679 // return expression
11680 return ExprOrStmt (std::move (expr
));
11683 // crappy hack to do union "keyword"
11685 if (t
->get_str () == "union"
11686 && lexer
.peek_token (1)->get_id () == IDENTIFIER
)
11688 std::unique_ptr
<AST::VisItem
> item (
11689 parse_vis_item (std::move (outer_attrs
)));
11690 return ExprOrStmt (std::move (item
));
11691 // or should this go straight to parsing union?
11693 else if (t
->get_str () == "macro_rules")
11695 // macro_rules! macro item
11696 std::unique_ptr
<AST::MacroItem
> item (
11697 parse_macro_item (std::move (outer_attrs
)));
11698 return ExprOrStmt (std::move (item
));
11700 else if (lexer
.peek_token (1)->get_id () == SCOPE_RESOLUTION
11701 || lexer
.peek_token (1)->get_id () == EXCLAM
11702 || lexer
.peek_token (1)->get_id () == LEFT_CURLY
)
11704 /* path (probably) or macro invocation or struct or enum, so
11705 * probably a macro invocation semi decide how to parse - probably
11706 * parse path and then get macro from it */
11708 // FIXME: old code was good until composability was required
11709 // return parse_path_based_stmt_or_expr(std::move(outer_attrs));
11710 std::unique_ptr
<AST::ExprWithoutBlock
> expr
11711 = parse_expr_without_block (std::move (outer_attrs
));
11713 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
11715 // must be expression statement
11716 lexer
.skip_token ();
11718 std::unique_ptr
<AST::ExprStmtWithoutBlock
> stmt (
11719 new AST::ExprStmtWithoutBlock (std::move (expr
),
11721 return ExprOrStmt (std::move (stmt
));
11724 // return expression
11725 return ExprOrStmt (std::move (expr
));
11727 gcc_fallthrough ();
11728 // TODO: find out how to disable gcc "implicit fallthrough" warning
11730 /* expression statement (without block) or expression itself - parse
11731 * expression then make it statement if semi afterwards */
11733 std::unique_ptr
<AST::ExprWithoutBlock
> expr
11734 = parse_expr_without_block (std::move (outer_attrs
));
11736 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
11738 // must be expression statement
11739 lexer
.skip_token ();
11741 std::unique_ptr
<AST::ExprStmtWithoutBlock
> stmt (
11742 new AST::ExprStmtWithoutBlock (std::move (expr
),
11744 return ExprOrStmt (std::move (stmt
));
11747 // return expression
11748 return ExprOrStmt (std::move (expr
));
11753 /* Parses a statement or expression beginning with a path (i.e. macro,
11754 * struct/enum, or path expr) */
11755 template <typename ManagedTokenSource
>
11757 Parser
<ManagedTokenSource
>::parse_path_based_stmt_or_expr (
11758 AST::AttrVec outer_attrs
)
11760 // attempt to parse path
11761 Location stmt_or_expr_loc
= lexer
.peek_token ()->get_locus ();
11762 AST::PathInExpression path
= parse_path_in_expression ();
11764 // branch on next token
11765 const_TokenPtr t2
= lexer
.peek_token ();
11766 switch (t2
->get_id ())
11769 /* macro invocation or macro invocation semi - depends on whether
11770 * there is a final ';' */
11771 // convert path in expr to simple path (as that is used in macros)
11772 AST::SimplePath macro_path
= path
.as_simple_path ();
11773 if (macro_path
.is_empty ())
11775 Error
error (t2
->get_locus (),
11776 "failed to convert parsed path to simple "
11777 "path (for macro invocation or semi)");
11778 add_error (std::move (error
));
11780 return ExprOrStmt::create_error ();
11783 // skip exclamation mark
11784 lexer
.skip_token ();
11786 const_TokenPtr t3
= lexer
.peek_token ();
11787 Location tok_tree_loc
= t3
->get_locus ();
11789 AST::DelimType type
= AST::PARENS
;
11790 switch (t3
->get_id ())
11793 type
= AST::PARENS
;
11796 type
= AST::SQUARE
;
11803 Error (t3
->get_locus (),
11804 "unrecognised token %qs in macro invocation - (opening) "
11805 "delimiter expected",
11806 t3
->get_token_description ()));
11808 return ExprOrStmt::create_error ();
11810 lexer
.skip_token ();
11812 // parse actual token trees
11813 std::vector
<std::unique_ptr
<AST::TokenTree
>> token_trees
;
11815 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t3
)));
11816 token_trees
.push_back (std::move (delim_open
));
11818 t3
= lexer
.peek_token ();
11819 // parse token trees until the initial delimiter token is found again
11820 while (!token_id_matches_delims (t3
->get_id (), type
))
11822 std::unique_ptr
<AST::TokenTree
> tree
= parse_token_tree ();
11824 if (tree
== nullptr)
11826 Error
error (t3
->get_locus (),
11827 "failed to parse token tree for macro "
11828 "invocation (or semi) - "
11830 t3
->get_token_description ());
11831 add_error (std::move (error
));
11833 return ExprOrStmt::create_error ();
11836 token_trees
.push_back (std::move (tree
));
11838 t3
= lexer
.peek_token ();
11842 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t3
)));
11843 token_trees
.push_back (std::move (delim_close
));
11845 // parse end delimiters
11846 t3
= lexer
.peek_token ();
11847 if (token_id_matches_delims (t3
->get_id (), type
))
11849 // tokens match opening delimiter, so skip.
11850 lexer
.skip_token ();
11852 /* with curly bracketed macros, assume it is a macro invocation
11853 * unless a semicolon is explicitly put at the end. this is not
11854 * necessarily true (i.e. context-dependence) and so may have to
11855 * be fixed up via HACKs in semantic analysis (by checking whether
11856 * it is the last elem in the vector). */
11858 AST::DelimTokenTree
delim_tok_tree (type
, std::move (token_trees
),
11860 AST::MacroInvocData
invoc_data (std::move (macro_path
),
11861 std::move (delim_tok_tree
));
11863 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
11865 lexer
.skip_token ();
11867 std::unique_ptr
<AST::MacroInvocation
> stmt (
11868 new AST::MacroInvocation (std::move (invoc_data
),
11869 std::move (outer_attrs
),
11870 stmt_or_expr_loc
, true));
11871 return ExprOrStmt (std::move (stmt
));
11874 // otherwise, create macro invocation
11875 std::unique_ptr
<AST::MacroInvocation
> expr (
11876 new AST::MacroInvocation (std::move (invoc_data
),
11877 std::move (outer_attrs
),
11878 stmt_or_expr_loc
, false));
11879 return ExprOrStmt (std::move (expr
));
11883 // tokens don't match opening delimiters, so produce error
11886 "unexpected token %qs - expecting closing delimiter %qs (for a "
11887 "macro invocation)",
11888 t2
->get_token_description (),
11889 (type
== AST::PARENS
? ")" : (type
== AST::SQUARE
? "]" : "}")));
11890 add_error (std::move (error
));
11892 return ExprOrStmt::create_error ();
11896 /* definitely not a block:
11897 * path '{' ident ','
11898 * path '{' ident ':' [anything] ','
11899 * path '{' ident ':' [not a type]
11900 * otherwise, assume block expr and thus path */
11901 bool not_a_block
= lexer
.peek_token (1)->get_id () == IDENTIFIER
11902 && (lexer
.peek_token (2)->get_id () == COMMA
11903 || (lexer
.peek_token (2)->get_id () == COLON
11904 && (lexer
.peek_token (4)->get_id () == COMMA
11905 || !can_tok_start_type (
11906 lexer
.peek_token (3)->get_id ()))));
11907 std::unique_ptr
<AST::ExprWithoutBlock
> expr
= nullptr;
11911 /* assume struct expr struct (as struct-enum disambiguation
11912 * requires name lookup) again, make statement if final ';' */
11913 expr
= parse_struct_expr_struct_partial (std::move (path
),
11914 std::move (outer_attrs
));
11915 if (expr
== nullptr)
11917 Error
error (t2
->get_locus (),
11918 "failed to parse struct expr struct");
11919 add_error (std::move (error
));
11921 return ExprOrStmt::create_error ();
11926 // assume path - make statement if final ';'
11927 // lexer.skip_token();
11929 // HACK: add outer attrs to path
11930 path
.set_outer_attrs (std::move (outer_attrs
));
11931 expr
= std::unique_ptr
<AST::PathInExpression
> (
11932 new AST::PathInExpression (std::move (path
)));
11935 // determine if statement if ends with semicolon
11936 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
11939 lexer
.skip_token ();
11940 std::unique_ptr
<AST::ExprStmtWithoutBlock
> stmt (
11941 new AST::ExprStmtWithoutBlock (std::move (expr
),
11942 stmt_or_expr_loc
));
11943 return ExprOrStmt (std::move (stmt
));
11946 // otherwise, expression
11947 return ExprOrStmt (std::move (expr
));
11950 /* assume struct expr tuple (as struct-enum disambiguation requires
11951 * name lookup) again, make statement if final ';' */
11952 std::unique_ptr
<AST::CallExpr
> struct_expr
11953 = parse_struct_expr_tuple_partial (std::move (path
),
11954 std::move (outer_attrs
));
11955 if (struct_expr
== nullptr)
11957 Error
error (t2
->get_locus (), "failed to parse struct expr tuple");
11958 add_error (std::move (error
));
11960 return ExprOrStmt::create_error ();
11963 // determine if statement if ends with semicolon
11964 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
11967 lexer
.skip_token ();
11968 std::unique_ptr
<AST::ExprStmtWithoutBlock
> stmt (
11969 new AST::ExprStmtWithoutBlock (std::move (struct_expr
),
11970 stmt_or_expr_loc
));
11971 return ExprOrStmt (std::move (stmt
));
11974 // otherwise, expression
11975 return ExprOrStmt (std::move (struct_expr
));
11978 // assume path - make statement if final ';'
11979 // lexer.skip_token();
11981 // HACK: replace outer attributes in path
11982 path
.set_outer_attrs (std::move (outer_attrs
));
11983 std::unique_ptr
<AST::PathInExpression
> expr (
11984 new AST::PathInExpression (std::move (path
)));
11986 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
11988 lexer
.skip_token ();
11990 std::unique_ptr
<AST::ExprStmtWithoutBlock
> stmt (
11991 new AST::ExprStmtWithoutBlock (std::move (expr
),
11992 stmt_or_expr_loc
));
11993 return ExprOrStmt (std::move (stmt
));
11996 return ExprOrStmt (std::move (expr
));
12001 // Parses a struct expression field.
12002 template <typename ManagedTokenSource
>
12003 std::unique_ptr
<AST::StructExprField
>
12004 Parser
<ManagedTokenSource
>::parse_struct_expr_field ()
12006 const_TokenPtr t
= lexer
.peek_token ();
12007 switch (t
->get_id ())
12010 if (lexer
.peek_token (1)->get_id () == COLON
)
12012 // struct expr field with identifier and expr
12013 Identifier ident
= t
->get_str ();
12014 lexer
.skip_token (1);
12016 // parse expression (required)
12017 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
12018 if (expr
== nullptr)
12020 Error
error (t
->get_locus (),
12021 "failed to parse struct expression field with "
12022 "identifier and expression");
12023 add_error (std::move (error
));
12028 return std::unique_ptr
<AST::StructExprFieldIdentifierValue
> (
12029 new AST::StructExprFieldIdentifierValue (std::move (ident
),
12035 // struct expr field with identifier only
12036 Identifier ident
= t
->get_str ();
12037 lexer
.skip_token ();
12039 return std::unique_ptr
<AST::StructExprFieldIdentifier
> (
12040 new AST::StructExprFieldIdentifier (std::move (ident
),
12043 case INT_LITERAL
: {
12044 // parse tuple index field
12045 int index
= atoi (t
->get_str ().c_str ());
12046 lexer
.skip_token ();
12048 if (!skip_token (COLON
))
12054 // parse field expression (required)
12055 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
12056 if (expr
== nullptr)
12058 Error
error (t
->get_locus (),
12059 "failed to parse expr in struct (or enum) expr "
12060 "field with tuple index");
12061 add_error (std::move (error
));
12066 return std::unique_ptr
<AST::StructExprFieldIndexValue
> (
12067 new AST::StructExprFieldIndexValue (index
, std::move (expr
),
12071 /* this is a struct base and can't be parsed here, so just return
12072 * nothing without erroring */
12077 Error (t
->get_locus (),
12078 "unrecognised token %qs as first token of struct expr field - "
12079 "expected identifier or integer literal",
12080 t
->get_token_description ()));
12086 // Parses a macro invocation or macro invocation semi.
12087 template <typename ManagedTokenSource
>
12089 Parser
<ManagedTokenSource
>::parse_macro_invocation_maybe_semi (
12090 AST::AttrVec outer_attrs
)
12092 Location macro_locus
= lexer
.peek_token ()->get_locus ();
12093 AST::SimplePath macro_path
= parse_simple_path ();
12094 if (macro_path
.is_empty ())
12096 Error
error (lexer
.peek_token ()->get_locus (),
12097 "failed to parse simple path in macro invocation or semi");
12098 add_error (std::move (error
));
12100 return ExprOrStmt::create_error ();
12103 if (!skip_token (EXCLAM
))
12105 return ExprOrStmt::create_error ();
12108 const_TokenPtr t3
= lexer
.peek_token ();
12109 Location tok_tree_loc
= t3
->get_locus ();
12111 AST::DelimType type
= AST::PARENS
;
12112 switch (t3
->get_id ())
12115 type
= AST::PARENS
;
12118 type
= AST::SQUARE
;
12125 Error (t3
->get_locus (),
12126 "unrecognised token %qs in macro invocation - (opening) "
12127 "delimiter expected",
12128 t3
->get_token_description ()));
12130 return ExprOrStmt::create_error ();
12132 lexer
.skip_token ();
12134 // parse actual token trees
12135 std::vector
<std::unique_ptr
<AST::TokenTree
>> token_trees
;
12137 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t3
)));
12138 token_trees
.push_back (std::move (delim_open
));
12140 t3
= lexer
.peek_token ();
12141 // parse token trees until the initial delimiter token is found again
12142 while (!token_id_matches_delims (t3
->get_id (), type
))
12144 std::unique_ptr
<AST::TokenTree
> tree
= parse_token_tree ();
12146 if (tree
== nullptr)
12148 Error
error (t3
->get_locus (),
12149 "failed to parse token tree for macro invocation (or "
12150 "semi) - found %qs",
12151 t3
->get_token_description ());
12152 add_error (std::move (error
));
12154 return ExprOrStmt::create_error ();
12157 token_trees
.push_back (std::move (tree
));
12159 t3
= lexer
.peek_token ();
12162 = std::unique_ptr
<AST::Token
> (new AST::Token (std::move (t3
)));
12163 token_trees
.push_back (std::move (delim_close
));
12165 // parse end delimiters
12166 t3
= lexer
.peek_token ();
12167 if (token_id_matches_delims (t3
->get_id (), type
))
12169 // tokens match opening delimiter, so skip.
12170 lexer
.skip_token ();
12172 /* with curly bracketed macros, assume it is a macro invocation unless
12173 * a semicolon is explicitly put at the end. this is not necessarily
12174 * true (i.e. context-dependence) and so may have to be fixed up via
12175 * HACKs in semantic analysis (by checking whether it is the last elem
12176 * in the vector). */
12178 AST::DelimTokenTree
delim_tok_tree (type
, std::move (token_trees
),
12180 AST::MacroInvocData
invoc_data (std::move (macro_path
),
12181 std::move (delim_tok_tree
));
12183 if (lexer
.peek_token ()->get_id () == SEMICOLON
)
12185 lexer
.skip_token ();
12187 std::unique_ptr
<AST::MacroInvocation
> stmt (
12188 new AST::MacroInvocation (std::move (invoc_data
),
12189 std::move (outer_attrs
), macro_locus
,
12191 return ExprOrStmt (std::move (stmt
));
12194 // otherwise, create macro invocation
12195 std::unique_ptr
<AST::MacroInvocation
> expr (
12196 new AST::MacroInvocation (std::move (invoc_data
),
12197 std::move (outer_attrs
), macro_locus
));
12198 return ExprOrStmt (std::move (expr
));
12202 const_TokenPtr t
= lexer
.peek_token ();
12203 // tokens don't match opening delimiters, so produce error
12206 "unexpected token %qs - expecting closing delimiter %qs (for a "
12207 "macro invocation)",
12208 t
->get_token_description (),
12209 (type
== AST::PARENS
? ")" : (type
== AST::SQUARE
? "]" : "}")));
12210 add_error (std::move (error
));
12212 return ExprOrStmt::create_error ();
12216 // "Unexpected token" panic mode - flags gcc error at unexpected token
12217 template <typename ManagedTokenSource
>
12219 Parser
<ManagedTokenSource
>::unexpected_token (const_TokenPtr t
)
12221 Error
error (t
->get_locus (), "unexpected token %qs\n",
12222 t
->get_token_description ());
12223 add_error (std::move (error
));
12226 /* Crappy "error recovery" performed after error by skipping tokens until a
12227 * semi-colon is found */
12228 template <typename ManagedTokenSource
>
12230 Parser
<ManagedTokenSource
>::skip_after_semicolon ()
12232 const_TokenPtr t
= lexer
.peek_token ();
12234 while (t
->get_id () != END_OF_FILE
&& t
->get_id () != SEMICOLON
)
12236 lexer
.skip_token ();
12237 t
= lexer
.peek_token ();
12240 if (t
->get_id () == SEMICOLON
)
12241 lexer
.skip_token ();
12244 /* Checks if current token has inputted id - skips it and returns true if so,
12245 * diagnoses an error and returns false otherwise. */
12246 template <typename ManagedTokenSource
>
12248 Parser
<ManagedTokenSource
>::skip_token (TokenId token_id
)
12250 return expect_token (token_id
) != const_TokenPtr ();
12253 /* Checks if current token has inputted id - skips it and returns true if so,
12254 * returns false otherwise without diagnosing an error */
12255 template <typename ManagedTokenSource
>
12257 Parser
<ManagedTokenSource
>::maybe_skip_token (TokenId token_id
)
12259 if (lexer
.peek_token ()->get_id () != token_id
)
12262 return skip_token (token_id
);
12265 /* Checks the current token - if id is same as expected, skips and returns it,
12266 * otherwise diagnoses error and returns null. */
12267 template <typename ManagedTokenSource
>
12269 Parser
<ManagedTokenSource
>::expect_token (TokenId token_id
)
12271 const_TokenPtr t
= lexer
.peek_token ();
12272 if (t
->get_id () == token_id
)
12274 lexer
.skip_token ();
12279 Error
error (t
->get_locus (), "expecting %qs but %qs found",
12280 get_token_description (token_id
),
12281 t
->get_token_description ());
12282 add_error (std::move (error
));
12284 return const_TokenPtr ();
12288 // Skips all tokens until EOF or }. Don't use.
12289 template <typename ManagedTokenSource
>
12291 Parser
<ManagedTokenSource
>::skip_after_end ()
12293 const_TokenPtr t
= lexer
.peek_token ();
12295 while (t
->get_id () != END_OF_FILE
&& t
->get_id () != RIGHT_CURLY
)
12297 lexer
.skip_token ();
12298 t
= lexer
.peek_token ();
12301 if (t
->get_id () == RIGHT_CURLY
)
12303 lexer
.skip_token ();
12307 /* A slightly more aware error-handler that skips all tokens until it reaches
12308 * the end of the block scope (i.e. when left curly brackets = right curly
12309 * brackets). Note: assumes currently in the middle of a block. Use
12310 * skip_after_next_block to skip based on the assumption that the block
12311 * has not been entered yet. */
12312 template <typename ManagedTokenSource
>
12314 Parser
<ManagedTokenSource
>::skip_after_end_block ()
12316 const_TokenPtr t
= lexer
.peek_token ();
12317 int curly_count
= 1;
12319 while (curly_count
> 0 && t
->get_id () != END_OF_FILE
)
12321 switch (t
->get_id ())
12332 lexer
.skip_token ();
12333 t
= lexer
.peek_token ();
12337 /* Skips tokens until the end of the next block. i.e. assumes that the block
12338 * has not been entered yet. */
12339 template <typename ManagedTokenSource
>
12341 Parser
<ManagedTokenSource
>::skip_after_next_block ()
12343 const_TokenPtr t
= lexer
.peek_token ();
12345 // initial loop - skip until EOF if no left curlies encountered
12346 while (t
->get_id () != END_OF_FILE
&& t
->get_id () != LEFT_CURLY
)
12348 lexer
.skip_token ();
12350 t
= lexer
.peek_token ();
12353 // if next token is left, skip it and then skip after the block ends
12354 if (t
->get_id () == LEFT_CURLY
)
12356 lexer
.skip_token ();
12358 skip_after_end_block ();
12360 // otherwise, do nothing as EOF
12363 /* Skips all tokens until ] (the end of an attribute) - does not skip the ]
12364 * (as designed for attribute body use) */
12365 template <typename ManagedTokenSource
>
12367 Parser
<ManagedTokenSource
>::skip_after_end_attribute ()
12369 const_TokenPtr t
= lexer
.peek_token ();
12371 while (t
->get_id () != RIGHT_SQUARE
)
12373 lexer
.skip_token ();
12374 t
= lexer
.peek_token ();
12377 // Don't skip the RIGHT_SQUARE token
12380 /* Pratt parser impl of parse_expr. FIXME: this is only provisional and
12381 * probably will be changed.
12382 * FIXME: this may only parse expressions without blocks as they are the only
12383 * expressions to have precedence? */
12384 template <typename ManagedTokenSource
>
12385 std::unique_ptr
<AST::Expr
>
12386 Parser
<ManagedTokenSource
>::parse_expr (int right_binding_power
,
12387 AST::AttrVec outer_attrs
,
12388 ParseRestrictions restrictions
)
12390 const_TokenPtr current_token
= lexer
.peek_token ();
12391 // Special hack because we are allowed to return nullptr, in that case we
12392 // don't want to skip the token, since we don't actually parse it. But if
12393 // null isn't allowed it indicates an error, and we want to skip past that.
12394 // So return early if it is one of the tokens that ends an expression
12395 // (or at least cannot start a new expression).
12396 if (restrictions
.expr_can_be_null
)
12398 TokenId id
= current_token
->get_id ();
12399 if (id
== SEMICOLON
|| id
== RIGHT_PAREN
|| id
== RIGHT_CURLY
12400 || id
== RIGHT_SQUARE
)
12403 lexer
.skip_token ();
12405 // parse null denotation (unary part of expression)
12406 std::unique_ptr
<AST::Expr
> expr
12407 = null_denotation (current_token
, {}, restrictions
);
12409 if (expr
== nullptr)
12412 rust_debug ("null denotation is null; returning null for parse_expr");
12416 // stop parsing if find lower priority token - parse higher priority first
12417 while (right_binding_power
< left_binding_power (lexer
.peek_token ()))
12419 current_token
= lexer
.peek_token ();
12420 lexer
.skip_token ();
12422 expr
= left_denotation (current_token
, std::move (expr
),
12423 std::move (outer_attrs
), restrictions
);
12425 if (expr
== nullptr)
12428 rust_debug ("left denotation is null; returning null for parse_expr");
12437 // Parse expression with lowest left binding power.
12438 template <typename ManagedTokenSource
>
12439 std::unique_ptr
<AST::Expr
>
12440 Parser
<ManagedTokenSource
>::parse_expr (AST::AttrVec outer_attrs
,
12441 ParseRestrictions restrictions
)
12443 return parse_expr (LBP_LOWEST
, std::move (outer_attrs
), restrictions
);
12446 /* Determines action to take when finding token at beginning of expression.
12447 * FIXME: this may only apply to precedence-capable expressions (which are all
12448 * expressions without blocks), so make return type ExprWithoutBlock? It would
12449 * simplify stuff. */
12450 template <typename ManagedTokenSource
>
12451 std::unique_ptr
<AST::Expr
>
12452 Parser
<ManagedTokenSource
>::null_denotation (const_TokenPtr tok
,
12453 AST::AttrVec outer_attrs
,
12454 ParseRestrictions restrictions
)
12456 /* note: tok is previous character in input stream, not current one, as
12457 * parse_expr skips it before passing it in */
12459 /* as a Pratt parser (which works by decomposing expressions into a null
12460 * denotation and then a left denotation), null denotations handle primaries
12461 * and unary operands (but only prefix unary operands) */
12463 switch (tok
->get_id ())
12467 rust_debug ("beginning null denotation identifier handling");
12469 /* best option: parse as path, then extract identifier, macro,
12470 * struct/enum, or just path info from it */
12471 AST::PathInExpression path
= parse_path_in_expression_pratt (tok
);
12474 rust_debug ("finished null denotation identifier path parsing - "
12475 "next is branching");
12477 // branch on next token
12478 const_TokenPtr t
= lexer
.peek_token ();
12479 switch (t
->get_id ())
12483 return parse_macro_invocation_partial (std::move (path
),
12484 std::move (outer_attrs
),
12488 = lexer
.peek_token (1)->get_id () == IDENTIFIER
12489 && (lexer
.peek_token (2)->get_id () == COMMA
12490 || (lexer
.peek_token (2)->get_id () == COLON
12491 && (lexer
.peek_token (4)->get_id () == COMMA
12492 || !can_tok_start_type (
12493 lexer
.peek_token (3)->get_id ()))));
12495 /* definitely not a block:
12496 * path '{' ident ','
12497 * path '{' ident ':' [anything] ','
12498 * path '{' ident ':' [not a type]
12499 * otherwise, assume block expr and thus path */
12501 rust_debug ("values of lookahead: '%s' '%s' '%s' '%s' ",
12502 lexer
.peek_token (1)->get_token_description (),
12503 lexer
.peek_token (2)->get_token_description (),
12504 lexer
.peek_token (3)->get_token_description (),
12505 lexer
.peek_token (4)->get_token_description ());
12507 rust_debug ("can be struct expr: '%s', not a block: '%s'",
12508 restrictions
.can_be_struct_expr
? "true" : "false",
12509 not_a_block
? "true" : "false");
12511 // struct/enum expr struct
12512 if (!restrictions
.can_be_struct_expr
&& !not_a_block
)
12514 // HACK: add outer attrs to path
12515 path
.set_outer_attrs (std::move (outer_attrs
));
12516 return std::unique_ptr
<AST::PathInExpression
> (
12517 new AST::PathInExpression (std::move (path
)));
12519 return parse_struct_expr_struct_partial (std::move (path
),
12520 std::move (outer_attrs
));
12523 // struct/enum expr tuple
12524 if (!restrictions
.can_be_struct_expr
)
12526 // HACK: add outer attrs to path
12527 path
.set_outer_attrs (std::move (outer_attrs
));
12528 return std::unique_ptr
<AST::PathInExpression
> (
12529 new AST::PathInExpression (std::move (path
)));
12531 return parse_struct_expr_tuple_partial (std::move (path
),
12532 std::move (outer_attrs
));
12534 // assume path is returned if not single segment
12535 if (path
.is_single_segment ())
12537 // have to return an identifier expression or something, idk
12538 /* HACK: may have to become permanent, but this is my current
12539 * identifier expression */
12540 return std::unique_ptr
<AST::IdentifierExpr
> (
12541 new AST::IdentifierExpr (tok
->get_str (), {},
12542 tok
->get_locus ()));
12544 // HACK: add outer attrs to path
12545 path
.set_outer_attrs (std::move (outer_attrs
));
12546 return std::unique_ptr
<AST::PathInExpression
> (
12547 new AST::PathInExpression (std::move (path
)));
12549 gcc_unreachable ();
12551 /* FIXME: delegate to parse_literal_expr instead? would have to rejig
12552 * tokens and whatever. */
12553 /* FIXME: could also be path expression (and hence macro expression,
12554 * struct/enum expr) */
12557 // HACK: add outer attrs to path
12558 AST::QualifiedPathInExpression path
12559 = parse_qualified_path_in_expression (tok
->get_locus ());
12560 path
.set_outer_attrs (std::move (outer_attrs
));
12561 return std::unique_ptr
<AST::QualifiedPathInExpression
> (
12562 new AST::QualifiedPathInExpression (std::move (path
)));
12564 // FIXME: for literal exprs, should outer attrs be passed in or just
12567 // we should check the range, but ignore for now
12569 return std::unique_ptr
<AST::LiteralExpr
> (
12570 new AST::LiteralExpr (tok
->get_str (), AST::Literal::INT
,
12571 tok
->get_type_hint (), {}, tok
->get_locus ()));
12572 case FLOAT_LITERAL
:
12573 // encode as float?
12574 return std::unique_ptr
<AST::LiteralExpr
> (
12575 new AST::LiteralExpr (tok
->get_str (), AST::Literal::FLOAT
,
12576 tok
->get_type_hint (), {}, tok
->get_locus ()));
12577 case STRING_LITERAL
:
12578 return std::unique_ptr
<AST::LiteralExpr
> (
12579 new AST::LiteralExpr (tok
->get_str (), AST::Literal::STRING
,
12580 tok
->get_type_hint (), {}, tok
->get_locus ()));
12581 case BYTE_STRING_LITERAL
:
12582 return std::unique_ptr
<AST::LiteralExpr
> (
12583 new AST::LiteralExpr (tok
->get_str (), AST::Literal::BYTE_STRING
,
12584 tok
->get_type_hint (), {}, tok
->get_locus ()));
12586 return std::unique_ptr
<AST::LiteralExpr
> (
12587 new AST::LiteralExpr (tok
->get_str (), AST::Literal::CHAR
,
12588 tok
->get_type_hint (), {}, tok
->get_locus ()));
12589 case BYTE_CHAR_LITERAL
:
12590 return std::unique_ptr
<AST::LiteralExpr
> (
12591 new AST::LiteralExpr (tok
->get_str (), AST::Literal::BYTE
,
12592 tok
->get_type_hint (), {}, tok
->get_locus ()));
12594 return std::unique_ptr
<AST::LiteralExpr
> (
12595 new AST::LiteralExpr ("true", AST::Literal::BOOL
, tok
->get_type_hint (),
12596 {}, tok
->get_locus ()));
12597 case FALSE_LITERAL
:
12598 return std::unique_ptr
<AST::LiteralExpr
> (
12599 new AST::LiteralExpr ("false", AST::Literal::BOOL
,
12600 tok
->get_type_hint (), {}, tok
->get_locus ()));
12602 return parse_grouped_or_tuple_expr (std::move (outer_attrs
),
12603 tok
->get_locus ());
12605 /*case PLUS: { // unary plus operator
12606 // invoke parse_expr recursively with appropriate priority, etc. for
12607 below AST::Expr* expr = parse_expr(LBP_UNARY_PLUS);
12609 if (expr == nullptr)
12611 // can only apply to integer and float expressions
12612 if (expr->get_type() != integer_type_node || expr->get_type() !=
12613 float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
12614 plus must be int or float but it is %s", print_type(expr->get_type()));
12618 return Tree(expr, tok->get_locus());
12620 // Rust has no unary plus operator
12621 case MINUS
: { // unary minus
12622 ParseRestrictions entered_from_unary
;
12623 entered_from_unary
.entered_from_unary
= true;
12624 if (!restrictions
.can_be_struct_expr
)
12625 entered_from_unary
.can_be_struct_expr
= false;
12626 std::unique_ptr
<AST::Expr
> expr
12627 = parse_expr (LBP_UNARY_MINUS
, {}, entered_from_unary
);
12629 if (expr
== nullptr)
12631 // can only apply to integer and float expressions
12632 /*if (expr.get_type() != integer_type_node || expr.get_type() !=
12633 float_type_node) { rust_error_at(tok->get_locus(), "operand of unary
12634 minus must be int or float but it is %s",
12635 print_type(expr.get_type())); return Tree::error();
12637 /* FIXME: when implemented the "get type" method on expr, ensure it is
12638 * int or float type (except unsigned int). Actually, this would
12639 * probably have to be done in semantic analysis (as type checking).
12642 /* FIXME: allow outer attributes on these expressions by having an
12643 * outer attrs parameter in function*/
12644 return std::unique_ptr
<AST::NegationExpr
> (
12645 new AST::NegationExpr (std::move (expr
), NegationOperator::NEGATE
,
12646 std::move (outer_attrs
), tok
->get_locus ()));
12648 case EXCLAM
: { // logical or bitwise not
12649 ParseRestrictions entered_from_unary
;
12650 entered_from_unary
.entered_from_unary
= true;
12651 if (!restrictions
.can_be_struct_expr
)
12652 entered_from_unary
.can_be_struct_expr
= false;
12653 std::unique_ptr
<AST::Expr
> expr
12654 = parse_expr (LBP_UNARY_EXCLAM
, {}, entered_from_unary
);
12656 if (expr
== nullptr)
12658 // can only apply to boolean expressions
12659 /*if (expr.get_type() != boolean_type_node) {
12660 rust_error_at(tok->get_locus(),
12661 "operand of logical not must be a boolean but it is %s",
12662 print_type(expr.get_type()));
12663 return Tree::error();
12665 /* FIXME: type checking for boolean or integer expressions in semantic
12668 // FIXME: allow outer attributes on these expressions
12669 return std::unique_ptr
<AST::NegationExpr
> (
12670 new AST::NegationExpr (std::move (expr
), NegationOperator::NOT
,
12671 std::move (outer_attrs
), tok
->get_locus ()));
12674 /* pointer dereference only - HACK: as struct expressions should
12675 * always be value expressions, cannot be dereferenced */
12676 ParseRestrictions entered_from_unary
;
12677 entered_from_unary
.entered_from_unary
= true;
12678 entered_from_unary
.can_be_struct_expr
= false;
12679 std::unique_ptr
<AST::Expr
> expr
12680 = parse_expr (LBP_UNARY_ASTERISK
, {}, entered_from_unary
);
12681 // FIXME: allow outer attributes on expression
12682 return std::unique_ptr
<AST::DereferenceExpr
> (
12683 new AST::DereferenceExpr (std::move (expr
), std::move (outer_attrs
),
12684 tok
->get_locus ()));
12687 // (single) "borrow" expression - shared (mutable) or immutable
12688 std::unique_ptr
<AST::Expr
> expr
= nullptr;
12689 bool is_mut_borrow
= false;
12691 /* HACK: as struct expressions should always be value expressions,
12692 * cannot be referenced */
12693 ParseRestrictions entered_from_unary
;
12694 entered_from_unary
.entered_from_unary
= true;
12695 entered_from_unary
.can_be_struct_expr
= false;
12697 if (lexer
.peek_token ()->get_id () == MUT
)
12699 lexer
.skip_token ();
12700 expr
= parse_expr (LBP_UNARY_AMP_MUT
, {}, entered_from_unary
);
12701 is_mut_borrow
= true;
12705 expr
= parse_expr (LBP_UNARY_AMP
, {}, entered_from_unary
);
12708 // FIXME: allow outer attributes on expression
12709 return std::unique_ptr
<AST::BorrowExpr
> (
12710 new AST::BorrowExpr (std::move (expr
), is_mut_borrow
, false,
12711 std::move (outer_attrs
), tok
->get_locus ()));
12713 case LOGICAL_AND
: {
12714 // (double) "borrow" expression - shared (mutable) or immutable
12715 std::unique_ptr
<AST::Expr
> expr
= nullptr;
12716 bool is_mut_borrow
= false;
12718 ParseRestrictions entered_from_unary
;
12719 entered_from_unary
.entered_from_unary
= true;
12721 if (lexer
.peek_token ()->get_id () == MUT
)
12723 lexer
.skip_token ();
12724 expr
= parse_expr (LBP_UNARY_AMP_MUT
, {}, entered_from_unary
);
12725 is_mut_borrow
= true;
12729 expr
= parse_expr (LBP_UNARY_AMP
, {}, entered_from_unary
);
12732 // FIXME: allow outer attributes on expression
12733 return std::unique_ptr
<AST::BorrowExpr
> (
12734 new AST::BorrowExpr (std::move (expr
), is_mut_borrow
, true,
12735 std::move (outer_attrs
), tok
->get_locus ()));
12737 case SCOPE_RESOLUTION
: {
12738 // TODO: fix: this is for global paths, i.e. std::string::whatever
12739 Error
error (tok
->get_locus (),
12740 "found null denotation scope resolution operator, and "
12741 "have not written handling for it");
12742 add_error (std::move (error
));
12752 rust_debug ("beginning null denotation "
12753 "self/self-alias/dollar/crate/super handling");
12755 /* best option: parse as path, then extract identifier, macro,
12756 * struct/enum, or just path info from it */
12757 AST::PathInExpression path
= parse_path_in_expression_pratt (tok
);
12761 "just finished parsing path (going to disambiguate) - peeked "
12763 lexer
.peek_token ()->get_token_description ());
12765 // HACK: always make "self" by itself a path (regardless of next
12767 if (tok
->get_id () == SELF
&& path
.is_single_segment ())
12769 // HACK: add outer attrs to path
12770 path
.set_outer_attrs (std::move (outer_attrs
));
12771 return std::unique_ptr
<AST::PathInExpression
> (
12772 new AST::PathInExpression (std::move (path
)));
12775 // branch on next token
12776 const_TokenPtr t
= lexer
.peek_token ();
12777 switch (t
->get_id ())
12781 return parse_macro_invocation_partial (std::move (path
),
12782 std::move (outer_attrs
));
12784 // struct/enum expr struct
12785 rust_debug ("can_be_struct_expr: %s",
12786 restrictions
.can_be_struct_expr
? "true" : "false");
12789 = lexer
.peek_token (1)->get_id () == IDENTIFIER
12790 && (lexer
.peek_token (2)->get_id () == COMMA
12791 || (lexer
.peek_token (2)->get_id () == COLON
12792 && (lexer
.peek_token (4)->get_id () == COMMA
12793 || !can_tok_start_type (
12794 lexer
.peek_token (3)->get_id ()))));
12796 if (!restrictions
.can_be_struct_expr
&& !not_a_block
)
12798 // assume path is returned
12799 // HACK: add outer attributes to path
12800 path
.set_outer_attrs (std::move (outer_attrs
));
12801 return std::unique_ptr
<AST::PathInExpression
> (
12802 new AST::PathInExpression (std::move (path
)));
12804 return parse_struct_expr_struct_partial (std::move (path
),
12805 std::move (outer_attrs
));
12808 // struct/enum expr tuple
12809 if (!restrictions
.can_be_struct_expr
)
12811 // assume path is returned
12812 // HACK: add outer attributes to path
12813 path
.set_outer_attrs (std::move (outer_attrs
));
12814 return std::unique_ptr
<AST::PathInExpression
> (
12815 new AST::PathInExpression (std::move (path
)));
12817 return parse_struct_expr_tuple_partial (std::move (path
),
12818 std::move (outer_attrs
));
12820 // assume path is returned
12821 // HACK: add outer attributes to path
12822 path
.set_outer_attrs (std::move (outer_attrs
));
12823 return std::unique_ptr
<AST::PathInExpression
> (
12824 new AST::PathInExpression (std::move (path
)));
12826 gcc_unreachable ();
12831 // closure expression
12832 return parse_closure_expr_pratt (tok
, std::move (outer_attrs
));
12834 // either "range to" or "range full" expressions
12835 return parse_nud_range_exclusive_expr (tok
, std::move (outer_attrs
));
12837 // range to inclusive expr
12838 return parse_range_to_inclusive_expr (tok
, std::move (outer_attrs
));
12840 // FIXME: is this really a null denotation expression?
12841 return parse_return_expr (std::move (outer_attrs
), tok
->get_locus ());
12843 // FIXME: is this really a null denotation expression?
12844 return parse_break_expr (std::move (outer_attrs
), tok
->get_locus ());
12846 return parse_continue_expr (std::move (outer_attrs
), tok
->get_locus ());
12848 // ok - this is an expression with block for once.
12849 return parse_block_expr (std::move (outer_attrs
), tok
->get_locus ());
12851 // if or if let, so more lookahead to find out
12852 if (lexer
.peek_token (1)->get_id () == LET
)
12855 return parse_if_let_expr (std::move (outer_attrs
), tok
->get_locus ());
12860 return parse_if_expr (std::move (outer_attrs
), tok
->get_locus ());
12863 return parse_loop_expr (std::move (outer_attrs
), AST::LoopLabel::error (),
12864 tok
->get_locus ());
12866 return parse_while_loop_expr (std::move (outer_attrs
),
12867 AST::LoopLabel::error (),
12868 tok
->get_locus ());
12870 // also an expression with block
12871 return parse_match_expr (std::move (outer_attrs
), tok
->get_locus ());
12873 // array definition expr (not indexing)
12874 return parse_array_expr (std::move (outer_attrs
), tok
->get_locus ());
12876 return parse_unsafe_block_expr (std::move (outer_attrs
),
12877 tok
->get_locus ());
12879 if (!restrictions
.expr_can_be_null
)
12880 add_error (Error (tok
->get_locus (),
12881 "found unexpected token %qs in null denotation",
12882 tok
->get_token_description ()));
12887 /* Called for each token that can appear in infix (between) position. Can be
12888 * operators or other punctuation. Returns a function pointer to member
12889 * function that implements the left denotation for the token given. */
12890 template <typename ManagedTokenSource
>
12891 std::unique_ptr
<AST::Expr
>
12892 Parser
<ManagedTokenSource
>::left_denotation (const_TokenPtr tok
,
12893 std::unique_ptr
<AST::Expr
> left
,
12894 AST::AttrVec outer_attrs
,
12895 ParseRestrictions restrictions
)
12897 // Token passed in has already been skipped, so peek gives "next" token
12898 switch (tok
->get_id ())
12900 // FIXME: allow for outer attributes to be applied
12901 case QUESTION_MARK
: {
12902 Location left_locus
= left
->get_locus ();
12903 // error propagation expression - unary postfix
12904 return std::unique_ptr
<AST::ErrorPropagationExpr
> (
12905 new AST::ErrorPropagationExpr (std::move (left
),
12906 std::move (outer_attrs
), left_locus
));
12909 // sum expression - binary infix
12910 /*return parse_binary_plus_expr (tok, std::move (left),
12911 std::move (outer_attrs), restrictions);*/
12912 return parse_arithmetic_or_logical_expr (tok
, std::move (left
),
12913 std::move (outer_attrs
),
12914 ArithmeticOrLogicalOperator::ADD
,
12917 // difference expression - binary infix
12918 /*return parse_binary_minus_expr (tok, std::move (left),
12919 std::move (outer_attrs),
12921 return parse_arithmetic_or_logical_expr (
12922 tok
, std::move (left
), std::move (outer_attrs
),
12923 ArithmeticOrLogicalOperator::SUBTRACT
, restrictions
);
12925 // product expression - binary infix
12926 /*return parse_binary_mult_expr (tok, std::move (left),
12927 std::move (outer_attrs), restrictions);*/
12928 return parse_arithmetic_or_logical_expr (
12929 tok
, std::move (left
), std::move (outer_attrs
),
12930 ArithmeticOrLogicalOperator::MULTIPLY
, restrictions
);
12932 // quotient expression - binary infix
12933 /*return parse_binary_div_expr (tok, std::move (left),
12934 std::move (outer_attrs), restrictions);*/
12935 return parse_arithmetic_or_logical_expr (
12936 tok
, std::move (left
), std::move (outer_attrs
),
12937 ArithmeticOrLogicalOperator::DIVIDE
, restrictions
);
12939 // modulo expression - binary infix
12940 /*return parse_binary_mod_expr (tok, std::move (left),
12941 std::move (outer_attrs), restrictions);*/
12942 return parse_arithmetic_or_logical_expr (
12943 tok
, std::move (left
), std::move (outer_attrs
),
12944 ArithmeticOrLogicalOperator::MODULUS
, restrictions
);
12946 // logical or bitwise and expression - binary infix
12947 /*return parse_bitwise_and_expr (tok, std::move (left),
12948 std::move (outer_attrs), restrictions);*/
12949 return parse_arithmetic_or_logical_expr (
12950 tok
, std::move (left
), std::move (outer_attrs
),
12951 ArithmeticOrLogicalOperator::BITWISE_AND
, restrictions
);
12953 // logical or bitwise or expression - binary infix
12954 /*return parse_bitwise_or_expr (tok, std::move (left),
12955 std::move (outer_attrs), restrictions);*/
12956 return parse_arithmetic_or_logical_expr (
12957 tok
, std::move (left
), std::move (outer_attrs
),
12958 ArithmeticOrLogicalOperator::BITWISE_OR
, restrictions
);
12960 // logical or bitwise xor expression - binary infix
12961 /*return parse_bitwise_xor_expr (tok, std::move (left),
12962 std::move (outer_attrs), restrictions);*/
12963 return parse_arithmetic_or_logical_expr (
12964 tok
, std::move (left
), std::move (outer_attrs
),
12965 ArithmeticOrLogicalOperator::BITWISE_XOR
, restrictions
);
12967 // left shift expression - binary infix
12968 /*return parse_left_shift_expr (tok, std::move (left),
12969 std::move (outer_attrs), restrictions);*/
12970 return parse_arithmetic_or_logical_expr (
12971 tok
, std::move (left
), std::move (outer_attrs
),
12972 ArithmeticOrLogicalOperator::LEFT_SHIFT
, restrictions
);
12974 // right shift expression - binary infix
12975 /*return parse_right_shift_expr (tok, std::move (left),
12976 std::move (outer_attrs), restrictions);*/
12977 return parse_arithmetic_or_logical_expr (
12978 tok
, std::move (left
), std::move (outer_attrs
),
12979 ArithmeticOrLogicalOperator::RIGHT_SHIFT
, restrictions
);
12981 // equal to expression - binary infix (no associativity)
12982 /*return parse_binary_equal_expr (tok, std::move (left),
12983 std::move (outer_attrs),
12985 return parse_comparison_expr (tok
, std::move (left
),
12986 std::move (outer_attrs
),
12987 ComparisonOperator::EQUAL
, restrictions
);
12989 // not equal to expression - binary infix (no associativity)
12990 /*return parse_binary_not_equal_expr (tok, std::move (left),
12991 std::move (outer_attrs),
12993 return parse_comparison_expr (tok
, std::move (left
),
12994 std::move (outer_attrs
),
12995 ComparisonOperator::NOT_EQUAL
,
12998 // greater than expression - binary infix (no associativity)
12999 /*return parse_binary_greater_than_expr (tok, std::move (left),
13000 std::move (outer_attrs),
13002 return parse_comparison_expr (tok
, std::move (left
),
13003 std::move (outer_attrs
),
13004 ComparisonOperator::GREATER_THAN
,
13007 // less than expression - binary infix (no associativity)
13008 /*return parse_binary_less_than_expr (tok, std::move (left),
13009 std::move (outer_attrs),
13011 return parse_comparison_expr (tok
, std::move (left
),
13012 std::move (outer_attrs
),
13013 ComparisonOperator::LESS_THAN
,
13015 case GREATER_OR_EQUAL
:
13016 // greater than or equal to expression - binary infix (no associativity)
13017 /*return parse_binary_greater_equal_expr (tok, std::move (left),
13018 std::move (outer_attrs),
13020 return parse_comparison_expr (tok
, std::move (left
),
13021 std::move (outer_attrs
),
13022 ComparisonOperator::GREATER_OR_EQUAL
,
13024 case LESS_OR_EQUAL
:
13025 // less than or equal to expression - binary infix (no associativity)
13026 /*return parse_binary_less_equal_expr (tok, std::move (left),
13027 std::move (outer_attrs),
13029 return parse_comparison_expr (tok
, std::move (left
),
13030 std::move (outer_attrs
),
13031 ComparisonOperator::LESS_OR_EQUAL
,
13034 // lazy logical or expression - binary infix
13035 return parse_lazy_or_expr (tok
, std::move (left
), std::move (outer_attrs
),
13038 // lazy logical and expression - binary infix
13039 return parse_lazy_and_expr (tok
, std::move (left
),
13040 std::move (outer_attrs
), restrictions
);
13042 /* type cast expression - kind of binary infix (RHS is actually a
13044 return parse_type_cast_expr (tok
, std::move (left
),
13045 std::move (outer_attrs
), restrictions
);
13047 // assignment expression - binary infix (note right-to-left
13049 return parse_assig_expr (tok
, std::move (left
), std::move (outer_attrs
),
13052 /* plus-assignment expression - binary infix (note right-to-left
13053 * associativity) */
13054 /*return parse_plus_assig_expr (tok, std::move (left),
13055 std::move (outer_attrs), restrictions);*/
13056 return parse_compound_assignment_expr (tok
, std::move (left
),
13057 std::move (outer_attrs
),
13058 CompoundAssignmentOperator::ADD
,
13061 /* minus-assignment expression - binary infix (note right-to-left
13062 * associativity) */
13063 /*return parse_minus_assig_expr (tok, std::move (left),
13064 std::move (outer_attrs), restrictions);*/
13065 return parse_compound_assignment_expr (
13066 tok
, std::move (left
), std::move (outer_attrs
),
13067 CompoundAssignmentOperator::SUBTRACT
, restrictions
);
13069 /* multiply-assignment expression - binary infix (note right-to-left
13070 * associativity) */
13071 /*return parse_mult_assig_expr (tok, std::move (left),
13072 std::move (outer_attrs), restrictions);*/
13073 return parse_compound_assignment_expr (
13074 tok
, std::move (left
), std::move (outer_attrs
),
13075 CompoundAssignmentOperator::MULTIPLY
, restrictions
);
13077 /* division-assignment expression - binary infix (note right-to-left
13078 * associativity) */
13079 /*return parse_div_assig_expr (tok, std::move (left),
13080 std::move (outer_attrs), restrictions);*/
13081 return parse_compound_assignment_expr (tok
, std::move (left
),
13082 std::move (outer_attrs
),
13083 CompoundAssignmentOperator::DIVIDE
,
13086 /* modulo-assignment expression - binary infix (note right-to-left
13087 * associativity) */
13088 /*return parse_mod_assig_expr (tok, std::move (left),
13089 std::move (outer_attrs), restrictions);*/
13090 return parse_compound_assignment_expr (
13091 tok
, std::move (left
), std::move (outer_attrs
),
13092 CompoundAssignmentOperator::MODULUS
, restrictions
);
13094 /* bitwise and-assignment expression - binary infix (note right-to-left
13095 * associativity) */
13096 /*return parse_and_assig_expr (tok, std::move (left),
13097 std::move (outer_attrs), restrictions);*/
13098 return parse_compound_assignment_expr (
13099 tok
, std::move (left
), std::move (outer_attrs
),
13100 CompoundAssignmentOperator::BITWISE_AND
, restrictions
);
13102 /* bitwise or-assignment expression - binary infix (note right-to-left
13103 * associativity) */
13104 /*return parse_or_assig_expr (tok, std::move (left),
13105 std::move (outer_attrs), restrictions);*/
13106 return parse_compound_assignment_expr (
13107 tok
, std::move (left
), std::move (outer_attrs
),
13108 CompoundAssignmentOperator::BITWISE_OR
, restrictions
);
13110 /* bitwise xor-assignment expression - binary infix (note right-to-left
13111 * associativity) */
13112 /*return parse_xor_assig_expr (tok, std::move (left),
13113 std::move (outer_attrs), restrictions);*/
13114 return parse_compound_assignment_expr (
13115 tok
, std::move (left
), std::move (outer_attrs
),
13116 CompoundAssignmentOperator::BITWISE_XOR
, restrictions
);
13117 case LEFT_SHIFT_EQ
:
13118 /* left shift-assignment expression - binary infix (note right-to-left
13119 * associativity) */
13120 /*return parse_left_shift_assig_expr (tok, std::move (left),
13121 std::move (outer_attrs),
13123 return parse_compound_assignment_expr (
13124 tok
, std::move (left
), std::move (outer_attrs
),
13125 CompoundAssignmentOperator::LEFT_SHIFT
, restrictions
);
13126 case RIGHT_SHIFT_EQ
:
13127 /* right shift-assignment expression - binary infix (note right-to-left
13128 * associativity) */
13129 /*return parse_right_shift_assig_expr (tok, std::move (left),
13130 std::move (outer_attrs),
13132 return parse_compound_assignment_expr (
13133 tok
, std::move (left
), std::move (outer_attrs
),
13134 CompoundAssignmentOperator::RIGHT_SHIFT
, restrictions
);
13136 /* range exclusive expression - binary infix (no associativity)
13137 * either "range" or "range from" */
13138 return parse_led_range_exclusive_expr (tok
, std::move (left
),
13139 std::move (outer_attrs
),
13142 /* range inclusive expression - binary infix (no associativity)
13143 * unambiguously RangeInclusiveExpr */
13144 return parse_range_inclusive_expr (tok
, std::move (left
),
13145 std::move (outer_attrs
), restrictions
);
13146 case SCOPE_RESOLUTION
:
13147 // path expression - binary infix? FIXME should this even be parsed
13150 Error (tok
->get_locus (),
13151 "found scope resolution operator in left denotation "
13152 "function - this should probably be handled elsewhere"));
13156 /* field expression or method call - relies on parentheses after next
13157 * identifier or await if token after is "await" (unary postfix) or
13158 * tuple index if token after is a decimal int literal */
13160 const_TokenPtr next_tok
= lexer
.peek_token ();
13161 if (next_tok
->get_id () == IDENTIFIER
13162 && next_tok
->get_str () == "await")
13164 // await expression
13165 return parse_await_expr (tok
, std::move (left
),
13166 std::move (outer_attrs
));
13168 else if (next_tok
->get_id () == INT_LITERAL
)
13170 // tuple index expression - TODO check for decimal int literal
13171 return parse_tuple_index_expr (tok
, std::move (left
),
13172 std::move (outer_attrs
),
13175 else if (next_tok
->get_id () == IDENTIFIER
13176 && lexer
.peek_token (1)->get_id () != LEFT_PAREN
13177 && lexer
.peek_token (1)->get_id () != SCOPE_RESOLUTION
)
13179 /* field expression (or should be) - FIXME: scope resolution right
13180 * after identifier should always be method, I'm pretty sure */
13181 return parse_field_access_expr (tok
, std::move (left
),
13182 std::move (outer_attrs
),
13187 // method call (probably)
13188 return parse_method_call_expr (tok
, std::move (left
),
13189 std::move (outer_attrs
),
13194 // function call - method call is based on dot notation first
13195 return parse_function_call_expr (tok
, std::move (left
),
13196 std::move (outer_attrs
), restrictions
);
13198 // array or slice index expression (pseudo binary infix)
13199 return parse_index_expr (tok
, std::move (left
), std::move (outer_attrs
),
13201 case FLOAT_LITERAL
:
13202 /* HACK: get around lexer mis-identifying '.0' or '.1' or whatever as a
13203 * float literal - TODO does this happen anymore? It shouldn't. */
13204 return parse_tuple_index_expr_float (tok
, std::move (left
),
13205 std::move (outer_attrs
),
13208 add_error (Error (tok
->get_locus (),
13209 "found unexpected token %qs in left denotation",
13210 tok
->get_token_description ()));
13216 /* Returns the left binding power for the given ArithmeticOrLogicalExpr type.
13217 * TODO make constexpr? Would that even do anything useful? */
13218 inline binding_powers
13219 get_lbp_for_arithmetic_or_logical_expr (
13220 AST::ArithmeticOrLogicalExpr::ExprType expr_type
)
13224 case ArithmeticOrLogicalOperator::ADD
:
13226 case ArithmeticOrLogicalOperator::SUBTRACT
:
13228 case ArithmeticOrLogicalOperator::MULTIPLY
:
13230 case ArithmeticOrLogicalOperator::DIVIDE
:
13232 case ArithmeticOrLogicalOperator::MODULUS
:
13234 case ArithmeticOrLogicalOperator::BITWISE_AND
:
13236 case ArithmeticOrLogicalOperator::BITWISE_OR
:
13238 case ArithmeticOrLogicalOperator::BITWISE_XOR
:
13240 case ArithmeticOrLogicalOperator::LEFT_SHIFT
:
13241 return LBP_L_SHIFT
;
13242 case ArithmeticOrLogicalOperator::RIGHT_SHIFT
:
13243 return LBP_R_SHIFT
;
13245 // WTF? should not happen, this is an error
13246 gcc_unreachable ();
13252 // Parses an arithmetic or logical expression (with Pratt parsing).
13253 template <typename ManagedTokenSource
>
13254 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13255 Parser
<ManagedTokenSource
>::parse_arithmetic_or_logical_expr (
13256 const_TokenPtr
, std::unique_ptr
<AST::Expr
> left
, AST::AttrVec
,
13257 AST::ArithmeticOrLogicalExpr::ExprType expr_type
,
13258 ParseRestrictions restrictions
)
13260 // parse RHS (as tok has already been consumed in parse_expression)
13261 std::unique_ptr
<AST::Expr
> right
13262 = parse_expr (get_lbp_for_arithmetic_or_logical_expr (expr_type
),
13263 AST::AttrVec (), restrictions
);
13264 if (right
== nullptr)
13267 // TODO: check types. actually, do so during semantic analysis
13268 Location locus
= left
->get_locus ();
13270 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13271 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13272 expr_type
, locus
));
13275 // Parses a binary addition expression (with Pratt parsing).
13276 template <typename ManagedTokenSource
>
13277 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13278 Parser
<ManagedTokenSource
>::parse_binary_plus_expr (
13279 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13280 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13282 // parse RHS (as tok has already been consumed in parse_expression)
13283 std::unique_ptr
<AST::Expr
> right
13284 = parse_expr (LBP_PLUS
, AST::AttrVec (), restrictions
);
13285 if (right
== nullptr)
13288 // TODO: check types. actually, do so during semantic analysis
13289 Location locus
= left
->get_locus ();
13291 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13292 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13293 ArithmeticOrLogicalOperator::ADD
, locus
));
13296 // Parses a binary subtraction expression (with Pratt parsing).
13297 template <typename ManagedTokenSource
>
13298 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13299 Parser
<ManagedTokenSource
>::parse_binary_minus_expr (
13300 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13301 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13303 // parse RHS (as tok has already been consumed in parse_expression)
13304 std::unique_ptr
<AST::Expr
> right
13305 = parse_expr (LBP_MINUS
, AST::AttrVec (), restrictions
);
13306 if (right
== nullptr)
13309 // TODO: check types. actually, do so during semantic analysis
13310 Location locus
= left
->get_locus ();
13312 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13313 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13314 ArithmeticOrLogicalOperator::SUBTRACT
,
13318 // Parses a binary multiplication expression (with Pratt parsing).
13319 template <typename ManagedTokenSource
>
13320 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13321 Parser
<ManagedTokenSource
>::parse_binary_mult_expr (
13322 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13323 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13325 // parse RHS (as tok has already been consumed in parse_expression)
13326 std::unique_ptr
<AST::Expr
> right
13327 = parse_expr (LBP_MUL
, AST::AttrVec (), restrictions
);
13328 if (right
== nullptr)
13331 // TODO: check types. actually, do so during semantic analysis
13332 Location locus
= left
->get_locus ();
13334 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13335 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13336 ArithmeticOrLogicalOperator::MULTIPLY
,
13340 // Parses a binary division expression (with Pratt parsing).
13341 template <typename ManagedTokenSource
>
13342 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13343 Parser
<ManagedTokenSource
>::parse_binary_div_expr (
13344 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13345 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13347 // parse RHS (as tok has already been consumed in parse_expression)
13348 std::unique_ptr
<AST::Expr
> right
13349 = parse_expr (LBP_DIV
, AST::AttrVec (), restrictions
);
13350 if (right
== nullptr)
13353 // TODO: check types. actually, do so during semantic analysis
13354 Location locus
= left
->get_locus ();
13356 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13357 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13358 ArithmeticOrLogicalOperator::DIVIDE
,
13362 // Parses a binary modulo expression (with Pratt parsing).
13363 template <typename ManagedTokenSource
>
13364 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13365 Parser
<ManagedTokenSource
>::parse_binary_mod_expr (
13366 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13367 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13369 // parse RHS (as tok has already been consumed in parse_expression)
13370 std::unique_ptr
<AST::Expr
> right
13371 = parse_expr (LBP_MOD
, AST::AttrVec (), restrictions
);
13372 if (right
== nullptr)
13375 // TODO: check types. actually, do so during semantic analysis
13376 Location locus
= left
->get_locus ();
13378 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13379 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13380 ArithmeticOrLogicalOperator::MODULUS
,
13384 /* Parses a binary bitwise (or eager logical) and expression (with Pratt
13386 template <typename ManagedTokenSource
>
13387 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13388 Parser
<ManagedTokenSource
>::parse_bitwise_and_expr (
13389 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13390 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13392 // parse RHS (as tok has already been consumed in parse_expression)
13393 std::unique_ptr
<AST::Expr
> right
13394 = parse_expr (LBP_AMP
, AST::AttrVec (), restrictions
);
13395 if (right
== nullptr)
13398 // TODO: check types. actually, do so during semantic analysis
13399 Location locus
= left
->get_locus ();
13401 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13402 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13403 ArithmeticOrLogicalOperator::BITWISE_AND
,
13407 /* Parses a binary bitwise (or eager logical) or expression (with Pratt
13409 template <typename ManagedTokenSource
>
13410 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13411 Parser
<ManagedTokenSource
>::parse_bitwise_or_expr (
13412 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13413 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13415 // parse RHS (as tok has already been consumed in parse_expression)
13416 std::unique_ptr
<AST::Expr
> right
13417 = parse_expr (LBP_PIPE
, AST::AttrVec (), restrictions
);
13418 if (right
== nullptr)
13421 // TODO: check types. actually, do so during semantic analysis
13422 Location locus
= left
->get_locus ();
13424 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13425 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13426 ArithmeticOrLogicalOperator::BITWISE_OR
,
13430 /* Parses a binary bitwise (or eager logical) xor expression (with Pratt
13432 template <typename ManagedTokenSource
>
13433 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13434 Parser
<ManagedTokenSource
>::parse_bitwise_xor_expr (
13435 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13436 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13438 // parse RHS (as tok has already been consumed in parse_expression)
13439 std::unique_ptr
<AST::Expr
> right
13440 = parse_expr (LBP_CARET
, AST::AttrVec (), restrictions
);
13441 if (right
== nullptr)
13444 // TODO: check types. actually, do so during semantic analysis
13445 Location locus
= left
->get_locus ();
13447 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13448 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13449 ArithmeticOrLogicalOperator::BITWISE_XOR
,
13453 // Parses a binary left shift expression (with Pratt parsing).
13454 template <typename ManagedTokenSource
>
13455 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13456 Parser
<ManagedTokenSource
>::parse_left_shift_expr (
13457 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13458 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13460 // parse RHS (as tok has already been consumed in parse_expression)
13461 std::unique_ptr
<AST::Expr
> right
13462 = parse_expr (LBP_L_SHIFT
, AST::AttrVec (), restrictions
);
13463 if (right
== nullptr)
13466 // TODO: check types. actually, do so during semantic analysis
13467 Location locus
= left
->get_locus ();
13469 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13470 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13471 ArithmeticOrLogicalOperator::LEFT_SHIFT
,
13475 // Parses a binary right shift expression (with Pratt parsing).
13476 template <typename ManagedTokenSource
>
13477 std::unique_ptr
<AST::ArithmeticOrLogicalExpr
>
13478 Parser
<ManagedTokenSource
>::parse_right_shift_expr (
13479 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13480 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13482 // parse RHS (as tok has already been consumed in parse_expression)
13483 std::unique_ptr
<AST::Expr
> right
13484 = parse_expr (LBP_R_SHIFT
, AST::AttrVec (), restrictions
);
13485 if (right
== nullptr)
13488 // TODO: check types. actually, do so during semantic analysis
13489 Location locus
= left
->get_locus ();
13491 return std::unique_ptr
<AST::ArithmeticOrLogicalExpr
> (
13492 new AST::ArithmeticOrLogicalExpr (std::move (left
), std::move (right
),
13493 ArithmeticOrLogicalOperator::RIGHT_SHIFT
,
13497 /* Returns the left binding power for the given ComparisonExpr type.
13498 * TODO make constexpr? Would that even do anything useful? */
13499 inline binding_powers
13500 get_lbp_for_comparison_expr (AST::ComparisonExpr::ExprType expr_type
)
13504 case ComparisonOperator::EQUAL
:
13506 case ComparisonOperator::NOT_EQUAL
:
13507 return LBP_NOT_EQUAL
;
13508 case ComparisonOperator::GREATER_THAN
:
13509 return LBP_GREATER_THAN
;
13510 case ComparisonOperator::LESS_THAN
:
13511 return LBP_SMALLER_THAN
;
13512 case ComparisonOperator::GREATER_OR_EQUAL
:
13513 return LBP_GREATER_EQUAL
;
13514 case ComparisonOperator::LESS_OR_EQUAL
:
13515 return LBP_SMALLER_EQUAL
;
13517 // WTF? should not happen, this is an error
13518 gcc_unreachable ();
13524 /* Parses a ComparisonExpr of given type and LBP. TODO find a way to only
13525 * specify one and have the other looked up - e.g. specify ExprType and
13526 * binding power is looked up? */
13527 template <typename ManagedTokenSource
>
13528 std::unique_ptr
<AST::ComparisonExpr
>
13529 Parser
<ManagedTokenSource
>::parse_comparison_expr (
13530 const_TokenPtr
, std::unique_ptr
<AST::Expr
> left
, AST::AttrVec
,
13531 AST::ComparisonExpr::ExprType expr_type
, ParseRestrictions restrictions
)
13533 // parse RHS (as tok has already been consumed in parse_expression)
13534 std::unique_ptr
<AST::Expr
> right
13535 = parse_expr (get_lbp_for_comparison_expr (expr_type
), AST::AttrVec (),
13537 if (right
== nullptr)
13540 // TODO: check types. actually, do so during semantic analysis
13541 Location locus
= left
->get_locus ();
13543 return std::unique_ptr
<AST::ComparisonExpr
> (
13544 new AST::ComparisonExpr (std::move (left
), std::move (right
), expr_type
,
13548 // Parses a binary equal to expression (with Pratt parsing).
13549 template <typename ManagedTokenSource
>
13550 std::unique_ptr
<AST::ComparisonExpr
>
13551 Parser
<ManagedTokenSource
>::parse_binary_equal_expr (
13552 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13553 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13555 // parse RHS (as tok has already been consumed in parse_expression)
13556 std::unique_ptr
<AST::Expr
> right
13557 = parse_expr (LBP_EQUAL
, AST::AttrVec (), restrictions
);
13558 if (right
== nullptr)
13561 // TODO: check types. actually, do so during semantic analysis
13562 Location locus
= left
->get_locus ();
13564 return std::unique_ptr
<AST::ComparisonExpr
> (
13565 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13566 ComparisonOperator::EQUAL
, locus
));
13569 // Parses a binary not equal to expression (with Pratt parsing).
13570 template <typename ManagedTokenSource
>
13571 std::unique_ptr
<AST::ComparisonExpr
>
13572 Parser
<ManagedTokenSource
>::parse_binary_not_equal_expr (
13573 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13574 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13576 // parse RHS (as tok has already been consumed in parse_expression)
13577 std::unique_ptr
<AST::Expr
> right
13578 = parse_expr (LBP_NOT_EQUAL
, AST::AttrVec (), restrictions
);
13579 if (right
== nullptr)
13582 // TODO: check types. actually, do so during semantic analysis
13583 Location locus
= left
->get_locus ();
13585 return std::unique_ptr
<AST::ComparisonExpr
> (
13586 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13587 ComparisonOperator::NOT_EQUAL
, locus
));
13590 // Parses a binary greater than expression (with Pratt parsing).
13591 template <typename ManagedTokenSource
>
13592 std::unique_ptr
<AST::ComparisonExpr
>
13593 Parser
<ManagedTokenSource
>::parse_binary_greater_than_expr (
13594 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13595 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13597 // parse RHS (as tok has already been consumed in parse_expression)
13598 std::unique_ptr
<AST::Expr
> right
13599 = parse_expr (LBP_GREATER_THAN
, AST::AttrVec (), restrictions
);
13600 if (right
== nullptr)
13603 // TODO: check types. actually, do so during semantic analysis
13604 Location locus
= left
->get_locus ();
13606 return std::unique_ptr
<AST::ComparisonExpr
> (
13607 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13608 ComparisonOperator::GREATER_THAN
, locus
));
13611 // Parses a binary less than expression (with Pratt parsing).
13612 template <typename ManagedTokenSource
>
13613 std::unique_ptr
<AST::ComparisonExpr
>
13614 Parser
<ManagedTokenSource
>::parse_binary_less_than_expr (
13615 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13616 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13618 // parse RHS (as tok has already been consumed in parse_expression)
13619 std::unique_ptr
<AST::Expr
> right
13620 = parse_expr (LBP_SMALLER_THAN
, AST::AttrVec (), restrictions
);
13621 if (right
== nullptr)
13624 // TODO: check types. actually, do so during semantic analysis
13625 Location locus
= left
->get_locus ();
13627 return std::unique_ptr
<AST::ComparisonExpr
> (
13628 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13629 ComparisonOperator::LESS_THAN
, locus
));
13632 // Parses a binary greater than or equal to expression (with Pratt parsing).
13633 template <typename ManagedTokenSource
>
13634 std::unique_ptr
<AST::ComparisonExpr
>
13635 Parser
<ManagedTokenSource
>::parse_binary_greater_equal_expr (
13636 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13637 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13639 // parse RHS (as tok has already been consumed in parse_expression)
13640 std::unique_ptr
<AST::Expr
> right
13641 = parse_expr (LBP_GREATER_EQUAL
, AST::AttrVec (), restrictions
);
13642 if (right
== nullptr)
13645 // TODO: check types. actually, do so during semantic analysis
13646 Location locus
= left
->get_locus ();
13648 return std::unique_ptr
<AST::ComparisonExpr
> (
13649 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13650 ComparisonOperator::GREATER_OR_EQUAL
, locus
));
13653 // Parses a binary less than or equal to expression (with Pratt parsing).
13654 template <typename ManagedTokenSource
>
13655 std::unique_ptr
<AST::ComparisonExpr
>
13656 Parser
<ManagedTokenSource
>::parse_binary_less_equal_expr (
13657 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13658 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13660 // parse RHS (as tok has already been consumed in parse_expression)
13661 std::unique_ptr
<AST::Expr
> right
13662 = parse_expr (LBP_SMALLER_EQUAL
, AST::AttrVec (), restrictions
);
13663 if (right
== nullptr)
13666 // TODO: check types. actually, do so during semantic analysis
13667 Location locus
= left
->get_locus ();
13669 return std::unique_ptr
<AST::ComparisonExpr
> (
13670 new AST::ComparisonExpr (std::move (left
), std::move (right
),
13671 ComparisonOperator::LESS_OR_EQUAL
, locus
));
13674 // Parses a binary lazy boolean or expression (with Pratt parsing).
13675 template <typename ManagedTokenSource
>
13676 std::unique_ptr
<AST::LazyBooleanExpr
>
13677 Parser
<ManagedTokenSource
>::parse_lazy_or_expr (
13678 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13679 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13681 // parse RHS (as tok has already been consumed in parse_expression)
13682 std::unique_ptr
<AST::Expr
> right
13683 = parse_expr (LBP_LOGICAL_OR
, AST::AttrVec (), restrictions
);
13684 if (right
== nullptr)
13687 // TODO: check types. actually, do so during semantic analysis
13688 Location locus
= left
->get_locus ();
13690 return std::unique_ptr
<AST::LazyBooleanExpr
> (
13691 new AST::LazyBooleanExpr (std::move (left
), std::move (right
),
13692 LazyBooleanOperator::LOGICAL_OR
, locus
));
13695 // Parses a binary lazy boolean and expression (with Pratt parsing).
13696 template <typename ManagedTokenSource
>
13697 std::unique_ptr
<AST::LazyBooleanExpr
>
13698 Parser
<ManagedTokenSource
>::parse_lazy_and_expr (
13699 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13700 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13702 // parse RHS (as tok has already been consumed in parse_expression)
13703 std::unique_ptr
<AST::Expr
> right
13704 = parse_expr (LBP_LOGICAL_AND
, AST::AttrVec (), restrictions
);
13705 if (right
== nullptr)
13708 // TODO: check types. actually, do so during semantic analysis
13709 Location locus
= left
->get_locus ();
13711 return std::unique_ptr
<AST::LazyBooleanExpr
> (
13712 new AST::LazyBooleanExpr (std::move (left
), std::move (right
),
13713 LazyBooleanOperator::LOGICAL_AND
, locus
));
13716 // Parses a pseudo-binary infix type cast expression (with Pratt parsing).
13717 template <typename ManagedTokenSource
>
13718 std::unique_ptr
<AST::TypeCastExpr
>
13719 Parser
<ManagedTokenSource
>::parse_type_cast_expr (
13720 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> expr_to_cast
,
13721 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
,
13722 ParseRestrictions restrictions ATTRIBUTE_UNUSED
)
13724 // parse RHS (as tok has already been consumed in parse_expression)
13725 std::unique_ptr
<AST::TypeNoBounds
> type
= parse_type_no_bounds ();
13726 if (type
== nullptr)
13728 // FIXME: how do I get precedence put in here?
13730 // TODO: check types. actually, do so during semantic analysis
13731 Location locus
= expr_to_cast
->get_locus ();
13733 return std::unique_ptr
<AST::TypeCastExpr
> (
13734 new AST::TypeCastExpr (std::move (expr_to_cast
), std::move (type
), locus
));
13737 // Parses a binary assignment expression (with Pratt parsing).
13738 template <typename ManagedTokenSource
>
13739 std::unique_ptr
<AST::AssignmentExpr
>
13740 Parser
<ManagedTokenSource
>::parse_assig_expr (
13741 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13742 AST::AttrVec outer_attrs
, ParseRestrictions restrictions
)
13744 // parse RHS (as tok has already been consumed in parse_expression)
13745 std::unique_ptr
<AST::Expr
> right
13746 = parse_expr (LBP_ASSIG
- 1, AST::AttrVec (), restrictions
);
13747 if (right
== nullptr)
13749 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13751 // TODO: check types. actually, do so during semantic analysis
13752 Location locus
= left
->get_locus ();
13754 return std::unique_ptr
<AST::AssignmentExpr
> (
13755 new AST::AssignmentExpr (std::move (left
), std::move (right
),
13756 std::move (outer_attrs
), locus
));
13759 /* Returns the left binding power for the given CompoundAssignmentExpr type.
13760 * TODO make constexpr? Would that even do anything useful? */
13761 inline binding_powers
13762 get_lbp_for_compound_assignment_expr (
13763 AST::CompoundAssignmentExpr::ExprType expr_type
)
13767 case CompoundAssignmentOperator::ADD
:
13769 case CompoundAssignmentOperator::SUBTRACT
:
13771 case CompoundAssignmentOperator::MULTIPLY
:
13773 case CompoundAssignmentOperator::DIVIDE
:
13775 case CompoundAssignmentOperator::MODULUS
:
13777 case CompoundAssignmentOperator::BITWISE_AND
:
13779 case CompoundAssignmentOperator::BITWISE_OR
:
13781 case CompoundAssignmentOperator::BITWISE_XOR
:
13783 case CompoundAssignmentOperator::LEFT_SHIFT
:
13784 return LBP_L_SHIFT
;
13785 case CompoundAssignmentOperator::RIGHT_SHIFT
:
13786 return LBP_R_SHIFT
;
13788 // WTF? should not happen, this is an error
13789 gcc_unreachable ();
13795 // Parses a compound assignment expression (with Pratt parsing).
13796 template <typename ManagedTokenSource
>
13797 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13798 Parser
<ManagedTokenSource
>::parse_compound_assignment_expr (
13799 const_TokenPtr
, std::unique_ptr
<AST::Expr
> left
, AST::AttrVec
,
13800 AST::CompoundAssignmentExpr::ExprType expr_type
,
13801 ParseRestrictions restrictions
)
13803 // parse RHS (as tok has already been consumed in parse_expression)
13804 std::unique_ptr
<AST::Expr
> right
13805 = parse_expr (get_lbp_for_compound_assignment_expr (expr_type
) - 1,
13806 AST::AttrVec (), restrictions
);
13807 if (right
== nullptr)
13809 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13811 // TODO: check types. actually, do so during semantic analysis
13812 Location locus
= left
->get_locus ();
13814 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13815 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13816 expr_type
, locus
));
13819 // Parses a binary add-assignment expression (with Pratt parsing).
13820 template <typename ManagedTokenSource
>
13821 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13822 Parser
<ManagedTokenSource
>::parse_plus_assig_expr (
13823 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13824 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13826 // parse RHS (as tok has already been consumed in parse_expression)
13827 std::unique_ptr
<AST::Expr
> right
13828 = parse_expr (LBP_PLUS_ASSIG
- 1, AST::AttrVec (), restrictions
);
13829 if (right
== nullptr)
13831 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13833 // TODO: check types. actually, do so during semantic analysis
13834 Location locus
= left
->get_locus ();
13836 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13837 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13838 CompoundAssignmentOperator::ADD
, locus
));
13841 // Parses a binary minus-assignment expression (with Pratt parsing).
13842 template <typename ManagedTokenSource
>
13843 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13844 Parser
<ManagedTokenSource
>::parse_minus_assig_expr (
13845 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13846 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13848 // parse RHS (as tok has already been consumed in parse_expression)
13849 std::unique_ptr
<AST::Expr
> right
13850 = parse_expr (LBP_MINUS_ASSIG
- 1, AST::AttrVec (), restrictions
);
13851 if (right
== nullptr)
13853 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13855 // TODO: check types. actually, do so during semantic analysis
13856 Location locus
= left
->get_locus ();
13858 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13859 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13860 CompoundAssignmentOperator::SUBTRACT
,
13864 // Parses a binary multiplication-assignment expression (with Pratt parsing).
13865 template <typename ManagedTokenSource
>
13866 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13867 Parser
<ManagedTokenSource
>::parse_mult_assig_expr (
13868 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13869 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13871 // parse RHS (as tok has already been consumed in parse_expression)
13872 std::unique_ptr
<AST::Expr
> right
13873 = parse_expr (LBP_MULT_ASSIG
- 1, AST::AttrVec (), restrictions
);
13874 if (right
== nullptr)
13876 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13878 // TODO: check types. actually, do so during semantic analysis
13879 Location locus
= left
->get_locus ();
13881 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13882 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13883 CompoundAssignmentOperator::MULTIPLY
,
13887 // Parses a binary division-assignment expression (with Pratt parsing).
13888 template <typename ManagedTokenSource
>
13889 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13890 Parser
<ManagedTokenSource
>::parse_div_assig_expr (
13891 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13892 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13894 // parse RHS (as tok has already been consumed in parse_expression)
13895 std::unique_ptr
<AST::Expr
> right
13896 = parse_expr (LBP_DIV_ASSIG
- 1, AST::AttrVec (), restrictions
);
13897 if (right
== nullptr)
13899 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13901 // TODO: check types. actually, do so during semantic analysis
13902 Location locus
= left
->get_locus ();
13904 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13905 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13906 CompoundAssignmentOperator::DIVIDE
,
13910 // Parses a binary modulo-assignment expression (with Pratt parsing).
13911 template <typename ManagedTokenSource
>
13912 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13913 Parser
<ManagedTokenSource
>::parse_mod_assig_expr (
13914 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13915 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13917 // parse RHS (as tok has already been consumed in parse_expression)
13918 std::unique_ptr
<AST::Expr
> right
13919 = parse_expr (LBP_MOD_ASSIG
- 1, AST::AttrVec (), restrictions
);
13920 if (right
== nullptr)
13922 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13924 // TODO: check types. actually, do so during semantic analysis
13925 Location locus
= left
->get_locus ();
13927 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13928 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13929 CompoundAssignmentOperator::MODULUS
,
13933 // Parses a binary and-assignment expression (with Pratt parsing).
13934 template <typename ManagedTokenSource
>
13935 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13936 Parser
<ManagedTokenSource
>::parse_and_assig_expr (
13937 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13938 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13940 // parse RHS (as tok has already been consumed in parse_expression)
13941 std::unique_ptr
<AST::Expr
> right
13942 = parse_expr (LBP_AMP_ASSIG
- 1, AST::AttrVec (), restrictions
);
13943 if (right
== nullptr)
13945 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13947 // TODO: check types. actually, do so during semantic analysis
13948 Location locus
= left
->get_locus ();
13950 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13951 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13952 CompoundAssignmentOperator::BITWISE_AND
,
13956 // Parses a binary or-assignment expression (with Pratt parsing).
13957 template <typename ManagedTokenSource
>
13958 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13959 Parser
<ManagedTokenSource
>::parse_or_assig_expr (
13960 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13961 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13963 // parse RHS (as tok has already been consumed in parse_expression)
13964 std::unique_ptr
<AST::Expr
> right
13965 = parse_expr (LBP_PIPE_ASSIG
- 1, AST::AttrVec (), restrictions
);
13966 if (right
== nullptr)
13968 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13970 // TODO: check types. actually, do so during semantic analysis
13971 Location locus
= left
->get_locus ();
13973 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13974 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13975 CompoundAssignmentOperator::BITWISE_OR
,
13979 // Parses a binary xor-assignment expression (with Pratt parsing).
13980 template <typename ManagedTokenSource
>
13981 std::unique_ptr
<AST::CompoundAssignmentExpr
>
13982 Parser
<ManagedTokenSource
>::parse_xor_assig_expr (
13983 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
13984 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
13986 // parse RHS (as tok has already been consumed in parse_expression)
13987 std::unique_ptr
<AST::Expr
> right
13988 = parse_expr (LBP_CARET_ASSIG
- 1, AST::AttrVec (), restrictions
);
13989 if (right
== nullptr)
13991 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
13993 // TODO: check types. actually, do so during semantic analysis
13994 Location locus
= left
->get_locus ();
13996 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
13997 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
13998 CompoundAssignmentOperator::BITWISE_XOR
,
14002 // Parses a binary left shift-assignment expression (with Pratt parsing).
14003 template <typename ManagedTokenSource
>
14004 std::unique_ptr
<AST::CompoundAssignmentExpr
>
14005 Parser
<ManagedTokenSource
>::parse_left_shift_assig_expr (
14006 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
14007 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
14009 // parse RHS (as tok has already been consumed in parse_expression)
14010 std::unique_ptr
<AST::Expr
> right
14011 = parse_expr (LBP_L_SHIFT_ASSIG
- 1, AST::AttrVec (), restrictions
);
14012 if (right
== nullptr)
14014 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
14016 // TODO: check types. actually, do so during semantic analysis
14017 Location locus
= left
->get_locus ();
14019 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
14020 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
14021 CompoundAssignmentOperator::LEFT_SHIFT
,
14025 // Parses a binary right shift-assignment expression (with Pratt parsing).
14026 template <typename ManagedTokenSource
>
14027 std::unique_ptr
<AST::CompoundAssignmentExpr
>
14028 Parser
<ManagedTokenSource
>::parse_right_shift_assig_expr (
14029 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
14030 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
14032 // parse RHS (as tok has already been consumed in parse_expression)
14033 std::unique_ptr
<AST::Expr
> right
14034 = parse_expr (LBP_R_SHIFT_ASSIG
- 1, AST::AttrVec (), restrictions
);
14035 if (right
== nullptr)
14037 // FIXME: ensure right-associativity for this - 'LBP - 1' may do this?
14039 // TODO: check types. actually, do so during semantic analysis
14040 Location locus
= left
->get_locus ();
14042 return std::unique_ptr
<AST::CompoundAssignmentExpr
> (
14043 new AST::CompoundAssignmentExpr (std::move (left
), std::move (right
),
14044 CompoundAssignmentOperator::RIGHT_SHIFT
,
14048 // Parses a postfix unary await expression (with Pratt parsing).
14049 template <typename ManagedTokenSource
>
14050 std::unique_ptr
<AST::AwaitExpr
>
14051 Parser
<ManagedTokenSource
>::parse_await_expr (
14052 const_TokenPtr tok
, std::unique_ptr
<AST::Expr
> expr_to_await
,
14053 AST::AttrVec outer_attrs
)
14055 /* skip "await" identifier (as "." has already been consumed in
14056 * parse_expression) this assumes that the identifier was already identified
14058 if (!skip_token (IDENTIFIER
))
14060 Error
error (tok
->get_locus (), "failed to skip %<await%> in await expr "
14061 "- this is probably a deep issue");
14062 add_error (std::move (error
));
14068 // TODO: check inside async block in semantic analysis
14069 Location locus
= expr_to_await
->get_locus ();
14071 return std::unique_ptr
<AST::AwaitExpr
> (
14072 new AST::AwaitExpr (std::move (expr_to_await
), std::move (outer_attrs
),
14076 /* Parses an exclusive range ('..') in left denotation position (i.e.
14077 * RangeFromExpr or RangeFromToExpr). */
14078 template <typename ManagedTokenSource
>
14079 std::unique_ptr
<AST::RangeExpr
>
14080 Parser
<ManagedTokenSource
>::parse_led_range_exclusive_expr (
14081 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
14082 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
14084 // FIXME: this probably parses expressions accidently or whatever
14085 // try parsing RHS (as tok has already been consumed in parse_expression)
14086 // Can be nullptr, in which case it is a RangeFromExpr, otherwise a
14087 // RangeFromToExpr.
14088 restrictions
.expr_can_be_null
= true;
14089 std::unique_ptr
<AST::Expr
> right
14090 = parse_expr (LBP_DOT_DOT
, AST::AttrVec (), restrictions
);
14092 Location locus
= left
->get_locus ();
14094 if (right
== nullptr)
14097 return std::unique_ptr
<AST::RangeFromExpr
> (
14098 new AST::RangeFromExpr (std::move (left
), locus
));
14102 return std::unique_ptr
<AST::RangeFromToExpr
> (
14103 new AST::RangeFromToExpr (std::move (left
), std::move (right
), locus
));
14105 // FIXME: make non-associative
14108 /* Parses an exclusive range ('..') in null denotation position (i.e.
14109 * RangeToExpr or RangeFullExpr). */
14110 template <typename ManagedTokenSource
>
14111 std::unique_ptr
<AST::RangeExpr
>
14112 Parser
<ManagedTokenSource
>::parse_nud_range_exclusive_expr (
14113 const_TokenPtr tok
, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
)
14115 // FIXME: this probably parses expressions accidently or whatever
14116 // try parsing RHS (as tok has already been consumed in parse_expression)
14117 std::unique_ptr
<AST::Expr
> right
= parse_expr (LBP_DOT_DOT
, AST::AttrVec ());
14119 Location locus
= tok
->get_locus ();
14121 if (right
== nullptr)
14124 return std::unique_ptr
<AST::RangeFullExpr
> (
14125 new AST::RangeFullExpr (locus
));
14129 return std::unique_ptr
<AST::RangeToExpr
> (
14130 new AST::RangeToExpr (std::move (right
), locus
));
14132 // FIXME: make non-associative
14135 // Parses a full binary range inclusive expression.
14136 template <typename ManagedTokenSource
>
14137 std::unique_ptr
<AST::RangeFromToInclExpr
>
14138 Parser
<ManagedTokenSource
>::parse_range_inclusive_expr (
14139 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> left
,
14140 AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
, ParseRestrictions restrictions
)
14142 // parse RHS (as tok has already been consumed in parse_expression)
14143 std::unique_ptr
<AST::Expr
> right
14144 = parse_expr (LBP_DOT_DOT_EQ
, AST::AttrVec (), restrictions
);
14145 if (right
== nullptr)
14147 // FIXME: make non-associative
14149 // TODO: check types. actually, do so during semantic analysis
14150 Location locus
= left
->get_locus ();
14152 return std::unique_ptr
<AST::RangeFromToInclExpr
> (
14153 new AST::RangeFromToInclExpr (std::move (left
), std::move (right
), locus
));
14156 // Parses an inclusive range-to prefix unary expression.
14157 template <typename ManagedTokenSource
>
14158 std::unique_ptr
<AST::RangeToInclExpr
>
14159 Parser
<ManagedTokenSource
>::parse_range_to_inclusive_expr (
14160 const_TokenPtr tok
, AST::AttrVec outer_attrs ATTRIBUTE_UNUSED
)
14162 // parse RHS (as tok has already been consumed in parse_expression)
14163 std::unique_ptr
<AST::Expr
> right
= parse_expr (LBP_DOT_DOT_EQ
);
14164 if (right
== nullptr)
14166 // FIXME: make non-associative
14168 // TODO: check types. actually, do so during semantic analysis
14170 return std::unique_ptr
<AST::RangeToInclExpr
> (
14171 new AST::RangeToInclExpr (std::move (right
), tok
->get_locus ()));
14174 // Parses a pseudo-binary infix tuple index expression.
14175 template <typename ManagedTokenSource
>
14176 std::unique_ptr
<AST::TupleIndexExpr
>
14177 Parser
<ManagedTokenSource
>::parse_tuple_index_expr (
14178 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> tuple_expr
,
14179 AST::AttrVec outer_attrs
, ParseRestrictions restrictions ATTRIBUTE_UNUSED
)
14181 // parse int literal (as token already skipped)
14182 const_TokenPtr index_tok
= expect_token (INT_LITERAL
);
14183 if (index_tok
== nullptr)
14187 std::string index
= index_tok
->get_str ();
14189 // convert to integer
14190 if (!index_tok
->is_pure_decimal ())
14192 Error
error (index_tok
->get_locus (),
14193 "tuple index should be a pure decimal literal");
14194 add_error (std::move (error
));
14196 int index_int
= atoi (index
.c_str ());
14198 Location locus
= tuple_expr
->get_locus ();
14200 return std::unique_ptr
<AST::TupleIndexExpr
> (
14201 new AST::TupleIndexExpr (std::move (tuple_expr
), index_int
,
14202 std::move (outer_attrs
), locus
));
14205 // Parses a pseudo-binary infix array (or slice) index expression.
14206 template <typename ManagedTokenSource
>
14207 std::unique_ptr
<AST::ArrayIndexExpr
>
14208 Parser
<ManagedTokenSource
>::parse_index_expr (
14209 const_TokenPtr
, std::unique_ptr
<AST::Expr
> array_expr
,
14210 AST::AttrVec outer_attrs
, ParseRestrictions
)
14212 // parse RHS (as tok has already been consumed in parse_expression)
14213 /*std::unique_ptr<AST::Expr> index_expr
14214 = parse_expr (LBP_ARRAY_REF, AST::AttrVec (),
14216 // TODO: conceptually, should treat [] as brackets, so just parse all expr
14217 std::unique_ptr
<AST::Expr
> index_expr
= parse_expr ();
14218 if (index_expr
== nullptr)
14221 // skip ']' at end of array
14222 if (!skip_token (RIGHT_SQUARE
))
14228 // TODO: check types. actually, do so during semantic analysis
14229 Location locus
= array_expr
->get_locus ();
14231 return std::unique_ptr
<AST::ArrayIndexExpr
> (
14232 new AST::ArrayIndexExpr (std::move (array_expr
), std::move (index_expr
),
14233 std::move (outer_attrs
), locus
));
14236 // Parses a pseudo-binary infix struct field access expression.
14237 template <typename ManagedTokenSource
>
14238 std::unique_ptr
<AST::FieldAccessExpr
>
14239 Parser
<ManagedTokenSource
>::parse_field_access_expr (
14240 const_TokenPtr tok ATTRIBUTE_UNUSED
, std::unique_ptr
<AST::Expr
> struct_expr
,
14241 AST::AttrVec outer_attrs
, ParseRestrictions restrictions ATTRIBUTE_UNUSED
)
14243 /* get field name identifier (assume that this is a field access expr and
14244 * not await, for instance) */
14245 const_TokenPtr ident_tok
= expect_token (IDENTIFIER
);
14246 if (ident_tok
== nullptr)
14249 Identifier ident
= ident_tok
->get_str ();
14251 Location locus
= struct_expr
->get_locus ();
14253 // TODO: check types. actually, do so during semantic analysis
14254 return std::unique_ptr
<AST::FieldAccessExpr
> (
14255 new AST::FieldAccessExpr (std::move (struct_expr
), std::move (ident
),
14256 std::move (outer_attrs
), locus
));
14259 // Parses a pseudo-binary infix method call expression.
14260 template <typename ManagedTokenSource
>
14261 std::unique_ptr
<AST::MethodCallExpr
>
14262 Parser
<ManagedTokenSource
>::parse_method_call_expr (
14263 const_TokenPtr tok
, std::unique_ptr
<AST::Expr
> receiver_expr
,
14264 AST::AttrVec outer_attrs
, ParseRestrictions
)
14266 // parse path expr segment
14267 AST::PathExprSegment segment
= parse_path_expr_segment ();
14268 if (segment
.is_error ())
14270 Error
error (tok
->get_locus (),
14271 "failed to parse path expr segment of method call expr");
14272 add_error (std::move (error
));
14277 // skip left parentheses
14278 if (!skip_token (LEFT_PAREN
))
14283 // parse method params (if they exist)
14284 std::vector
<std::unique_ptr
<AST::Expr
>> params
;
14286 const_TokenPtr t
= lexer
.peek_token ();
14287 while (t
->get_id () != RIGHT_PAREN
)
14289 std::unique_ptr
<AST::Expr
> param
= parse_expr ();
14290 if (param
== nullptr)
14292 Error
error (t
->get_locus (),
14293 "failed to parse method param in method call");
14294 add_error (std::move (error
));
14298 params
.push_back (std::move (param
));
14300 if (lexer
.peek_token ()->get_id () != COMMA
)
14303 lexer
.skip_token ();
14304 t
= lexer
.peek_token ();
14307 // skip right paren
14308 if (!skip_token (RIGHT_PAREN
))
14313 // TODO: check types. actually do so in semantic analysis pass.
14314 Location locus
= receiver_expr
->get_locus ();
14316 return std::unique_ptr
<AST::MethodCallExpr
> (
14317 new AST::MethodCallExpr (std::move (receiver_expr
), std::move (segment
),
14318 std::move (params
), std::move (outer_attrs
),
14322 // Parses a pseudo-binary infix function call expression.
14323 template <typename ManagedTokenSource
>
14324 std::unique_ptr
<AST::CallExpr
>
14325 Parser
<ManagedTokenSource
>::parse_function_call_expr (
14326 const_TokenPtr
, std::unique_ptr
<AST::Expr
> function_expr
,
14327 AST::AttrVec outer_attrs
, ParseRestrictions
)
14329 // parse function params (if they exist)
14330 std::vector
<std::unique_ptr
<AST::Expr
>> params
;
14332 const_TokenPtr t
= lexer
.peek_token ();
14333 while (t
->get_id () != RIGHT_PAREN
)
14335 std::unique_ptr
<AST::Expr
> param
= parse_expr ();
14336 if (param
== nullptr)
14338 Error
error (t
->get_locus (),
14339 "failed to parse function param in function call");
14340 add_error (std::move (error
));
14344 params
.push_back (std::move (param
));
14346 if (lexer
.peek_token ()->get_id () != COMMA
)
14349 lexer
.skip_token ();
14350 t
= lexer
.peek_token ();
14353 // skip ')' at end of param list
14354 if (!skip_token (RIGHT_PAREN
))
14360 // TODO: check types. actually, do so during semantic analysis
14361 Location locus
= function_expr
->get_locus ();
14363 return std::unique_ptr
<AST::CallExpr
> (
14364 new AST::CallExpr (std::move (function_expr
), std::move (params
),
14365 std::move (outer_attrs
), locus
));
14368 /* Parses a macro invocation with a path in expression already parsed (but not
14370 template <typename ManagedTokenSource
>
14371 std::unique_ptr
<AST::MacroInvocation
>
14372 Parser
<ManagedTokenSource
>::parse_macro_invocation_partial (
14373 AST::PathInExpression path
, AST::AttrVec outer_attrs
,
14374 ParseRestrictions restrictions
)
14376 // macro invocation
14377 if (!skip_token (EXCLAM
))
14382 // convert PathInExpression to SimplePath - if this isn't possible, error
14383 AST::SimplePath converted_path
= path
.as_simple_path ();
14384 if (converted_path
.is_empty ())
14386 Error
error (lexer
.peek_token ()->get_locus (),
14387 "failed to parse simple path in macro invocation");
14388 add_error (std::move (error
));
14393 AST::DelimTokenTree tok_tree
= parse_delim_token_tree ();
14395 rust_debug ("successfully parsed macro invocation (via partial)");
14397 Location macro_locus
= converted_path
.get_locus ();
14399 return std::unique_ptr
<AST::MacroInvocation
> (new AST::MacroInvocation (
14400 AST::MacroInvocData (std::move (converted_path
), std::move (tok_tree
)),
14401 std::move (outer_attrs
), macro_locus
, restrictions
.expr_can_be_stmt
));
14404 /* Parses a struct expr struct with a path in expression already parsed (but
14407 template <typename ManagedTokenSource
>
14408 std::unique_ptr
<AST::StructExprStruct
>
14409 Parser
<ManagedTokenSource
>::parse_struct_expr_struct_partial (
14410 AST::PathInExpression path
, AST::AttrVec outer_attrs
)
14412 // assume struct expr struct (as struct-enum disambiguation requires name
14413 // lookup) again, make statement if final ';'
14414 if (!skip_token (LEFT_CURLY
))
14419 // parse inner attributes
14420 AST::AttrVec inner_attrs
= parse_inner_attributes ();
14422 // branch based on next token
14423 const_TokenPtr t
= lexer
.peek_token ();
14424 Location path_locus
= path
.get_locus ();
14425 switch (t
->get_id ())
14428 // struct with no body
14429 lexer
.skip_token ();
14431 return std::unique_ptr
<AST::StructExprStruct
> (
14432 new AST::StructExprStruct (std::move (path
), std::move (inner_attrs
),
14433 std::move (outer_attrs
), path_locus
));
14435 /* technically this would give a struct base-only struct, but this
14436 * algorithm should work too. As such, AST type not happening. */
14438 case INT_LITERAL
: {
14439 // struct with struct expr fields
14441 // parse struct expr fields
14442 std::vector
<std::unique_ptr
<AST::StructExprField
>> fields
;
14444 while (t
->get_id () != RIGHT_CURLY
&& t
->get_id () != DOT_DOT
)
14446 std::unique_ptr
<AST::StructExprField
> field
14447 = parse_struct_expr_field ();
14448 if (field
== nullptr)
14450 Error
error (t
->get_locus (),
14451 "failed to parse struct (or enum) expr field");
14452 add_error (std::move (error
));
14458 rust_debug ("struct/enum expr field validated to not be null");
14460 fields
.push_back (std::move (field
));
14463 rust_debug ("struct/enum expr field pushed back");
14465 if (lexer
.peek_token ()->get_id () != COMMA
)
14468 rust_debug ("lack of comma detected in struct/enum expr "
14472 lexer
.skip_token ();
14475 rust_debug ("struct/enum expr fields comma skipped ");
14477 t
= lexer
.peek_token ();
14481 rust_debug ("struct/enum expr about to parse struct base ");
14483 // parse struct base if it exists
14484 AST::StructBase struct_base
= AST::StructBase::error ();
14485 if (lexer
.peek_token ()->get_id () == DOT_DOT
)
14487 Location dot_dot_location
= lexer
.peek_token ()->get_locus ();
14488 lexer
.skip_token ();
14490 // parse required struct base expr
14491 std::unique_ptr
<AST::Expr
> base_expr
= parse_expr ();
14492 if (base_expr
== nullptr)
14494 Error
error (lexer
.peek_token ()->get_locus (),
14495 "failed to parse struct base expression in struct "
14497 add_error (std::move (error
));
14503 rust_debug ("struct/enum expr - parsed and validated base expr");
14506 = AST::StructBase (std::move (base_expr
), dot_dot_location
);
14509 rust_debug ("assigned struct base to new struct base ");
14512 if (!skip_token (RIGHT_CURLY
))
14519 "struct/enum expr skipped right curly - done and ready to return");
14521 return std::unique_ptr
<AST::StructExprStructFields
> (
14522 new AST::StructExprStructFields (std::move (path
), std::move (fields
),
14523 path_locus
, std::move (struct_base
),
14524 std::move (inner_attrs
),
14525 std::move (outer_attrs
)));
14529 Error (t
->get_locus (),
14530 "unrecognised token %qs in struct (or enum) expression - "
14531 "expected %<}%>, identifier, integer literal, or %<..%>",
14532 t
->get_token_description ()));
14538 /* Parses a struct expr tuple with a path in expression already parsed (but
14541 * FIXME: this currently outputs a call expr, as they cannot be disambiguated.
14542 * A better solution would be to just get this to call that function directly.
14544 template <typename ManagedTokenSource
>
14545 std::unique_ptr
<AST::CallExpr
>
14546 Parser
<ManagedTokenSource
>::parse_struct_expr_tuple_partial (
14547 AST::PathInExpression path
, AST::AttrVec outer_attrs
)
14549 if (!skip_token (LEFT_PAREN
))
14554 AST::AttrVec inner_attrs
= parse_inner_attributes ();
14556 std::vector
<std::unique_ptr
<AST::Expr
>> exprs
;
14558 const_TokenPtr t
= lexer
.peek_token ();
14559 while (t
->get_id () != RIGHT_PAREN
)
14561 // parse expression (required)
14562 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
14563 if (expr
== nullptr)
14565 Error
error (t
->get_locus (), "failed to parse expression in "
14566 "struct (or enum) expression tuple");
14567 add_error (std::move (error
));
14571 exprs
.push_back (std::move (expr
));
14573 if (lexer
.peek_token ()->get_id () != COMMA
)
14576 lexer
.skip_token ();
14578 t
= lexer
.peek_token ();
14581 if (!skip_token (RIGHT_PAREN
))
14586 Location path_locus
= path
.get_locus ();
14588 auto pathExpr
= std::unique_ptr
<AST::PathInExpression
> (
14589 new AST::PathInExpression (std::move (path
)));
14591 return std::unique_ptr
<AST::CallExpr
> (
14592 new AST::CallExpr (std::move (pathExpr
), std::move (exprs
),
14593 std::move (outer_attrs
), path_locus
));
14596 /* Parses a path in expression with the first token passed as a parameter (as
14597 * it is skipped in token stream). Note that this only parses segment-first
14598 * paths, not global ones. */
14599 template <typename ManagedTokenSource
>
14600 AST::PathInExpression
14601 Parser
<ManagedTokenSource
>::parse_path_in_expression_pratt (const_TokenPtr tok
)
14603 // HACK-y way of making up for pratt-parsing consuming first token
14606 rust_debug ("current peek token when starting path pratt parse: '%s'",
14607 lexer
.peek_token ()->get_token_description ());
14609 // create segment vector
14610 std::vector
<AST::PathExprSegment
> segments
;
14612 std::string initial_str
;
14614 switch (tok
->get_id ())
14617 initial_str
= tok
->get_str ();
14620 initial_str
= "super";
14623 initial_str
= "self";
14626 initial_str
= "Self";
14629 initial_str
= "crate";
14632 if (lexer
.peek_token ()->get_id () == CRATE
)
14634 initial_str
= "$crate";
14637 gcc_fallthrough ();
14639 add_error (Error (tok
->get_locus (),
14640 "unrecognised token %qs in path in expression",
14641 tok
->get_token_description ()));
14643 return AST::PathInExpression::create_error ();
14646 // parse required initial segment
14647 AST::PathExprSegment
initial_segment (initial_str
, tok
->get_locus ());
14648 // parse generic args (and turbofish), if they exist
14649 /* use lookahead to determine if they actually exist (don't want to
14650 * accidently parse over next ident segment) */
14651 if (lexer
.peek_token ()->get_id () == SCOPE_RESOLUTION
14652 && lexer
.peek_token (1)->get_id () == LEFT_ANGLE
)
14654 // skip scope resolution
14655 lexer
.skip_token ();
14657 AST::GenericArgs generic_args
= parse_path_generic_args ();
14660 = AST::PathExprSegment (AST::PathIdentSegment (initial_str
,
14661 tok
->get_locus ()),
14662 tok
->get_locus (), std::move (generic_args
));
14664 if (initial_segment
.is_error ())
14666 // skip after somewhere?
14667 // don't necessarily throw error but yeah
14670 rust_debug ("initial segment is error - returning null");
14672 return AST::PathInExpression::create_error ();
14674 segments
.push_back (std::move (initial_segment
));
14676 // parse optional segments (as long as scope resolution operator exists)
14677 const_TokenPtr t
= lexer
.peek_token ();
14678 while (t
->get_id () == SCOPE_RESOLUTION
)
14680 // skip scope resolution operator
14681 lexer
.skip_token ();
14683 // parse the actual segment - it is an error if it doesn't exist now
14684 AST::PathExprSegment segment
= parse_path_expr_segment ();
14685 if (segment
.is_error ())
14687 // skip after somewhere?
14688 Error
error (t
->get_locus (),
14689 "could not parse path expression segment");
14690 add_error (std::move (error
));
14692 return AST::PathInExpression::create_error ();
14695 segments
.push_back (std::move (segment
));
14697 t
= lexer
.peek_token ();
14702 "current token (just about to return path to null denotation): '%s'",
14703 lexer
.peek_token ()->get_token_description ());
14705 return AST::PathInExpression (std::move (segments
), {}, tok
->get_locus (),
14709 // Parses a closure expression with pratt parsing (from null denotation).
14710 template <typename ManagedTokenSource
>
14711 std::unique_ptr
<AST::ClosureExpr
>
14712 Parser
<ManagedTokenSource
>::parse_closure_expr_pratt (const_TokenPtr tok
,
14713 AST::AttrVec outer_attrs
)
14715 // TODO: does this need pratt parsing (for precedence)? probably not, but
14717 Location locus
= tok
->get_locus ();
14718 bool has_move
= false;
14719 if (tok
->get_id () == MOVE
)
14722 tok
= lexer
.peek_token ();
14723 lexer
.skip_token ();
14724 // skip token and reassign
14727 // handle parameter list
14728 std::vector
<AST::ClosureParam
> params
;
14730 switch (tok
->get_id ())
14733 // no parameters, don't skip token
14736 // actually may have parameters
14737 // don't skip token
14738 const_TokenPtr t
= lexer
.peek_token ();
14739 while (t
->get_id () != PIPE
)
14741 AST::ClosureParam param
= parse_closure_param ();
14742 if (param
.is_error ())
14744 // TODO is this really an error?
14745 Error
error (t
->get_locus (), "could not parse closure param");
14746 add_error (std::move (error
));
14750 params
.push_back (std::move (param
));
14752 if (lexer
.peek_token ()->get_id () != COMMA
)
14754 // not an error but means param list is done
14758 lexer
.skip_token ();
14760 t
= lexer
.peek_token ();
14763 if (!skip_token (PIPE
))
14770 add_error (Error (tok
->get_locus (),
14771 "unexpected token %qs in closure expression - expected "
14773 tok
->get_token_description ()));
14779 // again branch based on next token
14780 tok
= lexer
.peek_token ();
14781 if (tok
->get_id () == RETURN_TYPE
)
14783 // must be return type closure with block expr
14785 // skip "return type" token
14786 lexer
.skip_token ();
14788 // parse actual type, which is required
14789 std::unique_ptr
<AST::TypeNoBounds
> type
= parse_type_no_bounds ();
14790 if (type
== nullptr)
14793 Error
error (tok
->get_locus (), "failed to parse type for closure");
14794 add_error (std::move (error
));
14800 // parse block expr, which is required
14801 std::unique_ptr
<AST::BlockExpr
> block
= parse_block_expr ();
14802 if (block
== nullptr)
14805 Error
error (lexer
.peek_token ()->get_locus (),
14806 "failed to parse block expr in closure");
14807 add_error (std::move (error
));
14813 return std::unique_ptr
<AST::ClosureExprInnerTyped
> (
14814 new AST::ClosureExprInnerTyped (std::move (type
), std::move (block
),
14815 std::move (params
), locus
, has_move
,
14816 std::move (outer_attrs
)));
14820 // must be expr-only closure
14822 // parse expr, which is required
14823 std::unique_ptr
<AST::Expr
> expr
= parse_expr ();
14824 if (expr
== nullptr)
14826 Error
error (tok
->get_locus (),
14827 "failed to parse expression in closure");
14828 add_error (std::move (error
));
14834 return std::unique_ptr
<AST::ClosureExprInner
> (
14835 new AST::ClosureExprInner (std::move (expr
), std::move (params
), locus
,
14836 has_move
, std::move (outer_attrs
)));
14840 /* Parses a tuple index expression (pratt-parsed) from a 'float' token as a
14841 * result of lexer misidentification. */
14842 template <typename ManagedTokenSource
>
14843 std::unique_ptr
<AST::TupleIndexExpr
>
14844 Parser
<ManagedTokenSource
>::parse_tuple_index_expr_float (
14845 const_TokenPtr tok
, std::unique_ptr
<AST::Expr
> tuple_expr
,
14846 AST::AttrVec outer_attrs
, ParseRestrictions restrictions ATTRIBUTE_UNUSED
)
14848 // only works on float literals
14849 if (tok
->get_id () != FLOAT_LITERAL
)
14853 rust_debug ("exact string form of float: '%s'", tok
->get_str ().c_str ());
14855 // get float string and remove dot and initial 0
14856 std::string index_str
= tok
->get_str ();
14857 index_str
.erase (index_str
.begin ());
14859 // get int from string
14860 int index
= atoi (index_str
.c_str ());
14862 Location locus
= tuple_expr
->get_locus ();
14864 return std::unique_ptr
<AST::TupleIndexExpr
> (
14865 new AST::TupleIndexExpr (std::move (tuple_expr
), index
,
14866 std::move (outer_attrs
), locus
));
14869 // Returns true if the next token is END, ELSE, or EOF;
14870 template <typename ManagedTokenSource
>
14872 Parser
<ManagedTokenSource
>::done_end_or_else ()
14874 const_TokenPtr t
= lexer
.peek_token ();
14875 return (t
->get_id () == RIGHT_CURLY
|| t
->get_id () == ELSE
14876 || t
->get_id () == END_OF_FILE
);
14879 // Returns true if the next token is END or EOF.
14880 template <typename ManagedTokenSource
>
14882 Parser
<ManagedTokenSource
>::done_end ()
14884 const_TokenPtr t
= lexer
.peek_token ();
14885 return (t
->get_id () == RIGHT_CURLY
|| t
->get_id () == END_OF_FILE
);
14888 // Dumps lexer output to stderr.
14889 template <typename ManagedTokenSource
>
14891 Parser
<ManagedTokenSource
>::debug_dump_lex_output (std::ostream
&out
)
14893 /* TODO: a better implementation of "lexer dump" (as in dump what was
14894 * actually tokenised) would actually be to "write" a token to a file every
14895 * time skip_token() here was called. This would reflect the parser
14896 * modifications to the token stream, such as fixing the template angle
14899 const_TokenPtr tok
= lexer
.peek_token ();
14903 if (tok
->get_id () == Rust::END_OF_FILE
)
14906 bool has_text
= tok
->get_id () == Rust::IDENTIFIER
14907 || tok
->get_id () == Rust::INT_LITERAL
14908 || tok
->get_id () == Rust::FLOAT_LITERAL
14909 || tok
->get_id () == Rust::STRING_LITERAL
14910 || tok
->get_id () == Rust::CHAR_LITERAL
14911 || tok
->get_id () == Rust::BYTE_STRING_LITERAL
14912 || tok
->get_id () == Rust::BYTE_CHAR_LITERAL
;
14914 Location loc
= tok
->get_locus ();
14917 out
<< tok
->token_id_to_str ();
14918 out
<< has_text
? (std::string (", text=") + tok
->get_str ()
14919 + std::string (", typehint=")
14920 + std::string (tok
->get_type_hint_str ()))
14922 out
<< lexer
.get_line_map ()->to_string (loc
);
14924 lexer
.skip_token ();
14925 tok
= lexer
.peek_token ();
14929 // Parses crate and dumps AST to stderr, recursively.
14930 template <typename ManagedTokenSource
>
14932 Parser
<ManagedTokenSource
>::debug_dump_ast_output (AST::Crate
&crate
,
14935 out
<< crate
.as_string ();
14937 } // namespace Rust