LCOV - code coverage report
Current view: top level - gcc/rust/parse - rust-parse-impl-pattern.hxx (source / functions) Coverage Total Hit
Test: gcc.info Lines: 66.7 % 655 437
Test Date: 2026-02-28 14:20:25 Functions: 69.2 % 26 18
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2025-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : /* DO NOT INCLUDE ANYWHERE - this is automatically included
      20              :  *   by rust-parse-impl.h
      21              :  * This is also the reason why there are no include guards. */
      22              : 
      23              : #include "rust-parse.h"
      24              : 
      25              : namespace Rust {
      26              : 
      27              : template <typename ManagedTokenSource>
      28              : std::unique_ptr<AST::Pattern>
      29        27826 : Parser<ManagedTokenSource>::parse_pattern ()
      30              : {
      31        27826 :   location_t start_locus = lexer.peek_token ()->get_locus ();
      32              : 
      33              :   /* skip optional starting pipe */
      34        27826 :   maybe_skip_token (PIPE);
      35              : 
      36        27826 :   auto first = parse_pattern_no_alt ();
      37              : 
      38        55652 :   if (lexer.peek_token ()->get_id () != PIPE)
      39              :     /* no alternates */
      40        27633 :     return first;
      41              : 
      42          193 :   std::vector<std::unique_ptr<AST::Pattern>> alts;
      43          193 :   if (first != nullptr)
      44          192 :     alts.push_back (std::move (first));
      45              : 
      46              :   do
      47              :     {
      48          211 :       lexer.skip_token ();
      49          211 :       auto follow = parse_pattern_no_alt ();
      50          211 :       if (follow != nullptr)
      51          211 :         alts.push_back (std::move (follow));
      52          211 :     }
      53              : 
      54          422 :   while (lexer.peek_token ()->get_id () == PIPE);
      55              : 
      56          193 :   if (alts.empty ())
      57            0 :     return nullptr;
      58              : 
      59              :   /* alternates */
      60              :   return std::unique_ptr<AST::Pattern> (
      61          193 :     new AST::AltPattern (std::move (alts), start_locus));
      62        27826 : }
      63              : 
      64              : // Parses a pattern without alternates ('|')
      65              : // (will further disambiguate any pattern).
      66              : template <typename ManagedTokenSource>
      67              : std::unique_ptr<AST::Pattern>
      68        28160 : Parser<ManagedTokenSource>::parse_pattern_no_alt ()
      69              : {
      70        28160 :   const_TokenPtr t = lexer.peek_token ();
      71        28160 :   switch (t->get_id ())
      72              :     {
      73           17 :     case TRUE_LITERAL:
      74           17 :       lexer.skip_token ();
      75           17 :       return std::unique_ptr<AST::LiteralPattern> (
      76           51 :         new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL,
      77              :                                  AST::Literal::BOOL, t->get_locus (),
      78           17 :                                  t->get_type_hint ()));
      79            9 :     case FALSE_LITERAL:
      80            9 :       lexer.skip_token ();
      81            9 :       return std::unique_ptr<AST::LiteralPattern> (
      82           27 :         new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL,
      83              :                                  AST::Literal::BOOL, t->get_locus (),
      84            9 :                                  t->get_type_hint ()));
      85          457 :     case CHAR_LITERAL:
      86              :     case BYTE_CHAR_LITERAL:
      87              :     case INT_LITERAL:
      88              :     case FLOAT_LITERAL:
      89          457 :       return parse_literal_or_range_pattern ();
      90            0 :     case STRING_LITERAL:
      91            0 :       lexer.skip_token ();
      92            0 :       return std::unique_ptr<AST::LiteralPattern> (
      93            0 :         new AST::LiteralPattern (t->get_str (), AST::Literal::STRING,
      94            0 :                                  t->get_locus (), t->get_type_hint ()));
      95            0 :     case BYTE_STRING_LITERAL:
      96            0 :       lexer.skip_token ();
      97            0 :       return std::unique_ptr<AST::LiteralPattern> (
      98            0 :         new AST::LiteralPattern (t->get_str (), AST::Literal::BYTE_STRING,
      99            0 :                                  t->get_locus (), t->get_type_hint ()));
     100            0 :     case RAW_STRING_LITERAL:
     101            0 :       lexer.skip_token ();
     102            0 :       return std::unique_ptr<AST::LiteralPattern> (
     103            0 :         new AST::LiteralPattern (t->get_str (), AST::Literal::RAW_STRING,
     104            0 :                                  t->get_locus (), t->get_type_hint ()));
     105              :     // raw string and raw byte string literals too if they are readded to
     106              :     // lexer
     107           26 :     case MINUS:
     108           52 :       if (lexer.peek_token (1)->get_id () == INT_LITERAL)
     109              :         {
     110           24 :           return parse_literal_or_range_pattern ();
     111              :         }
     112            4 :       else if (lexer.peek_token (1)->get_id () == FLOAT_LITERAL)
     113              :         {
     114            2 :           return parse_literal_or_range_pattern ();
     115              :         }
     116              :       else
     117              :         {
     118            0 :           Error error (t->get_locus (), "unexpected token %<-%> in pattern - "
     119              :                                         "did you forget an integer literal");
     120            0 :           add_error (std::move (error));
     121              : 
     122            0 :           return nullptr;
     123            0 :         }
     124         1058 :     case UNDERSCORE:
     125         1058 :       lexer.skip_token ();
     126         1058 :       return std::unique_ptr<AST::WildcardPattern> (
     127         1058 :         new AST::WildcardPattern (t->get_locus ()));
     128            0 :     case DOT_DOT:
     129            0 :       lexer.skip_token ();
     130            0 :       return std::unique_ptr<AST::RestPattern> (
     131            0 :         new AST::RestPattern (t->get_locus ()));
     132          924 :     case REF:
     133              :     case MUT:
     134          924 :       return parse_identifier_pattern ();
     135        25117 :     case IDENTIFIER:
     136              :       /* if identifier with no scope resolution afterwards, identifier
     137              :        * pattern. if scope resolution afterwards, path pattern (or range
     138              :        * pattern or struct pattern or tuple struct pattern) or macro
     139              :        * invocation */
     140        25117 :       return parse_ident_leading_pattern ();
     141           32 :     case AMP:
     142              :     case LOGICAL_AND:
     143              :       // reference pattern
     144           32 :       return parse_reference_pattern ();
     145          434 :     case LEFT_PAREN:
     146              :       // tuple pattern or grouped pattern
     147          434 :       return parse_grouped_or_tuple_pattern ();
     148           77 :     case LEFT_SQUARE:
     149              :       // slice pattern
     150           77 :       return parse_slice_pattern ();
     151            0 :     case LEFT_SHIFT:
     152              :     case LEFT_ANGLE:
     153              :       {
     154              :         // qualified path in expression or qualified range pattern bound
     155            0 :         AST::QualifiedPathInExpression path
     156              :           = parse_qualified_path_in_expression ();
     157              : 
     158            0 :         if (lexer.peek_token ()->get_id () == DOT_DOT_EQ
     159            0 :             || lexer.peek_token ()->get_id () == ELLIPSIS
     160            0 :             || lexer.peek_token ()->get_id () == DOT_DOT)
     161              :           {
     162              :             // qualified range pattern bound, so parse rest of range pattern
     163              :             AST::RangeKind kind
     164            0 :               = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
     165            0 :             lexer.skip_token ();
     166              : 
     167            0 :             std::unique_ptr<AST::RangePatternBoundQualPath> lower_bound (
     168            0 :               new AST::RangePatternBoundQualPath (std::move (path)));
     169            0 :             std::unique_ptr<AST::RangePatternBound> upper_bound
     170              :               = parse_range_pattern_bound ();
     171              : 
     172            0 :             return std::unique_ptr<AST::RangePattern> (
     173            0 :               new AST::RangePattern (std::move (lower_bound),
     174              :                                      std::move (upper_bound), kind,
     175            0 :                                      t->get_locus ()));
     176            0 :           }
     177              :         else
     178              :           {
     179              :             // just qualified path in expression
     180            0 :             return std::unique_ptr<AST::QualifiedPathInExpression> (
     181            0 :               new AST::QualifiedPathInExpression (std::move (path)));
     182              :           }
     183            0 :       }
     184            8 :     case SUPER:
     185              :     case SELF:
     186              :     case SELF_ALIAS:
     187              :     case CRATE:
     188              :     case SCOPE_RESOLUTION:
     189              :     case DOLLAR_SIGN:
     190              :       {
     191              :         // path in expression or range pattern bound
     192            8 :         AST::PathInExpression path = parse_path_in_expression ();
     193              : 
     194            8 :         const_TokenPtr next = lexer.peek_token ();
     195            8 :         switch (next->get_id ())
     196              :           {
     197            0 :           case DOT_DOT_EQ:
     198              :           case DOT_DOT:
     199              :           case ELLIPSIS:
     200              :             {
     201              :               // qualified range pattern bound, so parse rest of range pattern
     202            0 :               AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
     203            0 :               lexer.skip_token ();
     204              : 
     205            0 :               std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
     206            0 :                 new AST::RangePatternBoundPath (std::move (path)));
     207            0 :               std::unique_ptr<AST::RangePatternBound> upper_bound
     208              :                 = parse_range_pattern_bound ();
     209              : 
     210            0 :               return std::unique_ptr<AST::RangePattern> (
     211            0 :                 new AST::RangePattern (std::move (lower_bound),
     212              :                                        std::move (upper_bound), kind,
     213              :                                        next->get_locus ()));
     214            0 :             }
     215            0 :           case EXCLAM:
     216            0 :             return parse_macro_invocation_partial (std::move (path),
     217            0 :                                                    AST::AttrVec ());
     218            0 :           case LEFT_PAREN:
     219              :             {
     220              :               // tuple struct
     221            0 :               lexer.skip_token ();
     222              : 
     223              :               // parse items
     224            0 :               std::unique_ptr<AST::TupleStructItems> items
     225              :                 = parse_tuple_struct_items ();
     226            0 :               if (items == nullptr)
     227              :                 {
     228            0 :                   Error error (lexer.peek_token ()->get_locus (),
     229              :                                "failed to parse tuple struct items");
     230            0 :                   add_error (std::move (error));
     231              : 
     232            0 :                   return nullptr;
     233            0 :                 }
     234              : 
     235            0 :               if (!skip_token (RIGHT_PAREN))
     236              :                 {
     237            0 :                   return nullptr;
     238              :                 }
     239              : 
     240            0 :               return std::unique_ptr<AST::TupleStructPattern> (
     241            0 :                 new AST::TupleStructPattern (std::move (path),
     242            0 :                                              std::move (items)));
     243            0 :             }
     244            0 :           case LEFT_CURLY:
     245              :             {
     246              :               // struct
     247            0 :               lexer.skip_token ();
     248              : 
     249              :               // parse elements (optional)
     250            0 :               AST::StructPatternElements elems = parse_struct_pattern_elems ();
     251              : 
     252            0 :               if (!skip_token (RIGHT_CURLY))
     253              :                 {
     254            0 :                   return nullptr;
     255              :                 }
     256              : 
     257            0 :               return std::unique_ptr<AST::StructPattern> (
     258            0 :                 new AST::StructPattern (std::move (path), t->get_locus (),
     259            0 :                                         std::move (elems)));
     260            0 :             }
     261            8 :           default:
     262              :             // assume path in expression
     263            8 :             return std::unique_ptr<AST::PathInExpression> (
     264            8 :               new AST::PathInExpression (std::move (path)));
     265              :           }
     266            8 :       }
     267            1 :     default:
     268            1 :       add_error (Error (t->get_locus (), "unexpected token %qs in pattern",
     269              :                         t->get_token_description ()));
     270              : 
     271            1 :       return nullptr;
     272              :     }
     273        28160 : }
     274              : 
     275              : // Parses a single or double reference pattern.
     276              : template <typename ManagedTokenSource>
     277              : std::unique_ptr<AST::ReferencePattern>
     278           32 : Parser<ManagedTokenSource>::parse_reference_pattern ()
     279              : {
     280              :   // parse double or single ref
     281           32 :   bool is_double_ref = false;
     282           32 :   const_TokenPtr t = lexer.peek_token ();
     283           32 :   switch (t->get_id ())
     284              :     {
     285           23 :     case AMP:
     286              :       // still false
     287           23 :       lexer.skip_token ();
     288              :       break;
     289            9 :     case LOGICAL_AND:
     290            9 :       is_double_ref = true;
     291            9 :       lexer.skip_token ();
     292              :       break;
     293            0 :     default:
     294            0 :       add_error (Error (t->get_locus (),
     295              :                         "unexpected token %qs in reference pattern",
     296              :                         t->get_token_description ()));
     297              : 
     298            0 :       return nullptr;
     299              :     }
     300              : 
     301              :   // parse mut (if it exists)
     302           32 :   bool is_mut = false;
     303           64 :   if (lexer.peek_token ()->get_id () == MUT)
     304              :     {
     305            2 :       is_mut = true;
     306            2 :       lexer.skip_token ();
     307              :     }
     308              : 
     309              :   // parse pattern to get reference of (required)
     310           32 :   std::unique_ptr<AST::Pattern> pattern = parse_pattern_no_alt ();
     311           32 :   if (pattern == nullptr)
     312              :     {
     313            0 :       Error error (lexer.peek_token ()->get_locus (),
     314              :                    "failed to parse pattern in reference pattern");
     315            0 :       add_error (std::move (error));
     316              : 
     317              :       // skip somewhere?
     318            0 :       return nullptr;
     319            0 :     }
     320              : 
     321              :   return std::unique_ptr<AST::ReferencePattern> (
     322           32 :     new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref,
     323           32 :                                t->get_locus ()));
     324           32 : }
     325              : 
     326              : /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if
     327              :  * only a single element with no commas. */
     328              : template <typename ManagedTokenSource>
     329              : std::unique_ptr<AST::Pattern>
     330          434 : Parser<ManagedTokenSource>::parse_grouped_or_tuple_pattern ()
     331              : {
     332          434 :   location_t paren_locus = lexer.peek_token ()->get_locus ();
     333          434 :   skip_token (LEFT_PAREN);
     334              : 
     335              :   // detect '..' token (ranged with no lower range)
     336          868 :   if (lexer.peek_token ()->get_id () == DOT_DOT)
     337              :     {
     338            0 :       lexer.skip_token ();
     339              : 
     340              :       // parse new patterns while next token is a comma
     341            0 :       std::vector<std::unique_ptr<AST::Pattern>> patterns;
     342              : 
     343            0 :       const_TokenPtr t = lexer.peek_token ();
     344            0 :       while (t->get_id () == COMMA)
     345              :         {
     346            0 :           lexer.skip_token ();
     347              : 
     348              :           // break if next token is ')'
     349            0 :           if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
     350              :             {
     351              :               break;
     352              :             }
     353              : 
     354              :           // parse pattern, which is required
     355            0 :           std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
     356            0 :           if (pattern == nullptr)
     357              :             {
     358            0 :               Error error (
     359            0 :                 lexer.peek_token ()->get_locus (),
     360              :                 "failed to parse pattern inside ranged tuple pattern");
     361            0 :               add_error (std::move (error));
     362              : 
     363              :               // skip somewhere?
     364            0 :               return nullptr;
     365            0 :             }
     366            0 :           patterns.push_back (std::move (pattern));
     367              : 
     368            0 :           t = lexer.peek_token ();
     369              :         }
     370              : 
     371            0 :       if (!skip_token (RIGHT_PAREN))
     372              :         {
     373              :           // skip somewhere?
     374            0 :           return nullptr;
     375              :         }
     376              : 
     377              :       // create tuple pattern items with only upper pattern items
     378            0 :       std::unique_ptr<AST::TuplePatternItemsHasRest> items (
     379            0 :         new AST::TuplePatternItemsHasRest (
     380            0 :           std::vector<std::unique_ptr<AST::Pattern>> (), std::move (patterns)));
     381            0 :       return std::unique_ptr<AST::TuplePattern> (
     382            0 :         new AST::TuplePattern (std::move (items), paren_locus));
     383            0 :     }
     384          868 :   else if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
     385              :     {
     386            3 :       skip_token (RIGHT_PAREN);
     387            3 :       auto items = std::unique_ptr<AST::TuplePatternItemsNoRest> (
     388            3 :         new AST::TuplePatternItemsNoRest (
     389            3 :           std::vector<std::unique_ptr<AST::Pattern>> ()));
     390            3 :       return std::unique_ptr<AST::TuplePattern> (
     391            3 :         new AST::TuplePattern (std::move (items), paren_locus));
     392            3 :     }
     393              : 
     394              :   // parse initial pattern (required)
     395          431 :   std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
     396          431 :   if (initial_pattern == nullptr)
     397              :     {
     398            0 :       Error error (lexer.peek_token ()->get_locus (),
     399              :                    "failed to parse pattern in grouped or tuple pattern");
     400            0 :       add_error (std::move (error));
     401              : 
     402            0 :       return nullptr;
     403            0 :     }
     404              : 
     405              :   // branch on whether next token is a comma or not
     406          431 :   const_TokenPtr t = lexer.peek_token ();
     407          431 :   switch (t->get_id ())
     408              :     {
     409           44 :     case RIGHT_PAREN:
     410              :       // grouped pattern
     411           44 :       lexer.skip_token ();
     412              : 
     413           44 :       return std::unique_ptr<AST::GroupedPattern> (
     414           44 :         new AST::GroupedPattern (std::move (initial_pattern), paren_locus));
     415          386 :     case COMMA:
     416              :       {
     417              :         // tuple pattern
     418          386 :         lexer.skip_token ();
     419              : 
     420              :         // create vector of patterns
     421          386 :         std::vector<std::unique_ptr<AST::Pattern>> patterns;
     422          386 :         patterns.push_back (std::move (initial_pattern));
     423              : 
     424          386 :         t = lexer.peek_token ();
     425          772 :         while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT)
     426              :           {
     427              :             // parse pattern (required)
     428          386 :             std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
     429          386 :             if (pattern == nullptr)
     430              :               {
     431            0 :                 Error error (t->get_locus (),
     432              :                              "failed to parse pattern in tuple pattern");
     433            0 :                 add_error (std::move (error));
     434              : 
     435            0 :                 return nullptr;
     436            0 :               }
     437          386 :             patterns.push_back (std::move (pattern));
     438              : 
     439          772 :             if (lexer.peek_token ()->get_id () != COMMA)
     440              :               break;
     441              : 
     442           36 :             lexer.skip_token ();
     443           36 :             t = lexer.peek_token ();
     444              :           }
     445              : 
     446          386 :         t = lexer.peek_token ();
     447          386 :         if (t->get_id () == RIGHT_PAREN)
     448              :           {
     449              :             // non-ranged tuple pattern
     450          359 :             lexer.skip_token ();
     451              : 
     452          359 :             std::unique_ptr<AST::TuplePatternItemsNoRest> items (
     453          359 :               new AST::TuplePatternItemsNoRest (std::move (patterns)));
     454          359 :             return std::unique_ptr<AST::TuplePattern> (
     455          359 :               new AST::TuplePattern (std::move (items), paren_locus));
     456          359 :           }
     457           27 :         else if (t->get_id () == DOT_DOT)
     458              :           {
     459              :             // ranged tuple pattern
     460           27 :             lexer.skip_token ();
     461              : 
     462              :             // parse upper patterns
     463           27 :             std::vector<std::unique_ptr<AST::Pattern>> upper_patterns;
     464           27 :             t = lexer.peek_token ();
     465           59 :             while (t->get_id () == COMMA)
     466              :               {
     467           32 :                 lexer.skip_token ();
     468              : 
     469              :                 // break if end
     470           64 :                 if (lexer.peek_token ()->get_id () == RIGHT_PAREN)
     471              :                   break;
     472              : 
     473              :                 // parse pattern (required)
     474           32 :                 std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
     475           32 :                 if (pattern == nullptr)
     476              :                   {
     477            0 :                     Error error (lexer.peek_token ()->get_locus (),
     478              :                                  "failed to parse pattern in tuple pattern");
     479            0 :                     add_error (std::move (error));
     480              : 
     481            0 :                     return nullptr;
     482            0 :                   }
     483           32 :                 upper_patterns.push_back (std::move (pattern));
     484              : 
     485           32 :                 t = lexer.peek_token ();
     486              :               }
     487              : 
     488           27 :             if (!skip_token (RIGHT_PAREN))
     489              :               {
     490            0 :                 return nullptr;
     491              :               }
     492              : 
     493           27 :             std::unique_ptr<AST::TuplePatternItemsHasRest> items (
     494           27 :               new AST::TuplePatternItemsHasRest (std::move (patterns),
     495              :                                                  std::move (upper_patterns)));
     496           27 :             return std::unique_ptr<AST::TuplePattern> (
     497           27 :               new AST::TuplePattern (std::move (items), paren_locus));
     498           27 :           }
     499              :         else
     500              :           {
     501              :             // some kind of error
     502            0 :             Error error (t->get_locus (),
     503              :                          "failed to parse tuple pattern (probably) or maybe "
     504              :                          "grouped pattern");
     505            0 :             add_error (std::move (error));
     506              : 
     507            0 :             return nullptr;
     508            0 :           }
     509          386 :       }
     510            1 :     default:
     511              :       // error
     512            1 :       add_error (Error (t->get_locus (),
     513              :                         "unrecognised token %qs in grouped or tuple pattern "
     514              :                         "after first pattern",
     515              :                         t->get_token_description ()));
     516              : 
     517            1 :       return nullptr;
     518              :     }
     519          431 : }
     520              : 
     521              : /* Parses a slice pattern that can match arrays or slices. Parses the square
     522              :  * brackets too. */
     523              : template <typename ManagedTokenSource>
     524              : std::unique_ptr<AST::SlicePattern>
     525           77 : Parser<ManagedTokenSource>::parse_slice_pattern ()
     526              : {
     527          154 :   location_t square_locus = lexer.peek_token ()->get_locus ();
     528           77 :   std::vector<std::unique_ptr<AST::Pattern>> patterns;
     529           77 :   tl::optional<std::vector<std::unique_ptr<AST::Pattern>>> upper_patterns
     530              :     = tl::nullopt;
     531              : 
     532              :   // lambda function to determine which vector to push new patterns into
     533           77 :   auto get_pattern_ref
     534           75 :     = [&] () -> std::vector<std::unique_ptr<AST::Pattern>> & {
     535           75 :     return upper_patterns.has_value () ? upper_patterns.value () : patterns;
     536              :   };
     537              : 
     538           77 :   skip_token (LEFT_SQUARE);
     539              : 
     540          154 :   if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
     541              :     {
     542            1 :       skip_token (RIGHT_SQUARE);
     543            1 :       std::unique_ptr<AST::SlicePatternItemsNoRest> items (
     544            1 :         new AST::SlicePatternItemsNoRest (std::move (patterns)));
     545              :       return std::unique_ptr<AST::SlicePattern> (
     546            1 :         new AST::SlicePattern (std::move (items), square_locus));
     547            1 :     }
     548              : 
     549              :   // parse initial pattern (required)
     550          152 :   if (lexer.peek_token ()->get_id () == DOT_DOT)
     551              :     {
     552            1 :       lexer.skip_token ();
     553            1 :       upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
     554              :     }
     555              :   else
     556              :     {
     557              :       // Not a rest pattern `..`, parse normally
     558           75 :       std::unique_ptr<AST::Pattern> initial_pattern = parse_pattern ();
     559           75 :       if (initial_pattern == nullptr)
     560              :         {
     561            0 :           Error error (lexer.peek_token ()->get_locus (),
     562              :                        "failed to parse initial pattern in slice pattern");
     563            0 :           add_error (std::move (error));
     564              : 
     565            0 :           return nullptr;
     566            0 :         }
     567              : 
     568           75 :       patterns.push_back (std::move (initial_pattern));
     569           75 :     }
     570              : 
     571           76 :   const_TokenPtr t = lexer.peek_token ();
     572          194 :   while (t->get_id () == COMMA)
     573              :     {
     574          118 :       lexer.skip_token ();
     575              : 
     576              :       // break if end bracket
     577          236 :       if (lexer.peek_token ()->get_id () == RIGHT_SQUARE)
     578              :         break;
     579              : 
     580          236 :       if (lexer.peek_token ()->get_id () == DOT_DOT)
     581              :         {
     582           43 :           if (upper_patterns.has_value ())
     583              :             {
     584              :               // DOT_DOT has been parsed before
     585            0 :               Error error (lexer.peek_token ()->get_locus (), "%s",
     586              :                            "`..` can only be used once per slice pattern");
     587            0 :               add_error (std::move (error));
     588              : 
     589            0 :               return nullptr;
     590            0 :             }
     591           43 :           upper_patterns = std::vector<std::unique_ptr<AST::Pattern>> ();
     592           43 :           lexer.skip_token ();
     593           43 :           t = lexer.peek_token ();
     594           43 :           continue;
     595           43 :         }
     596              : 
     597              :       // parse pattern (required)
     598           75 :       std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
     599           75 :       if (pattern == nullptr)
     600              :         {
     601            0 :           Error error (lexer.peek_token ()->get_locus (),
     602              :                        "failed to parse pattern in slice pattern");
     603            0 :           add_error (std::move (error));
     604              : 
     605            0 :           return nullptr;
     606            0 :         }
     607           75 :       get_pattern_ref ().push_back (std::move (pattern));
     608              : 
     609           75 :       t = lexer.peek_token ();
     610              :     }
     611              : 
     612           76 :   if (!skip_token (RIGHT_SQUARE))
     613              :     {
     614            0 :       return nullptr;
     615              :     }
     616              : 
     617           76 :   if (upper_patterns.has_value ())
     618              :     {
     619              :       // Slice pattern with rest
     620           44 :       std::unique_ptr<AST::SlicePatternItemsHasRest> items (
     621           88 :         new AST::SlicePatternItemsHasRest (
     622           44 :           std::move (patterns), std::move (upper_patterns.value ())));
     623              :       return std::unique_ptr<AST::SlicePattern> (
     624           44 :         new AST::SlicePattern (std::move (items), square_locus));
     625           44 :     }
     626              : 
     627              :   // Rest-less slice pattern
     628           32 :   std::unique_ptr<AST::SlicePatternItemsNoRest> items (
     629           32 :     new AST::SlicePatternItemsNoRest (std::move (patterns)));
     630              :   return std::unique_ptr<AST::SlicePattern> (
     631           32 :     new AST::SlicePattern (std::move (items), square_locus));
     632          185 : }
     633              : 
     634              : /* Parses an identifier pattern (pattern that binds a value matched to a
     635              :  * variable). */
     636              : template <typename ManagedTokenSource>
     637              : std::unique_ptr<AST::IdentifierPattern>
     638          924 : Parser<ManagedTokenSource>::parse_identifier_pattern ()
     639              : {
     640          924 :   location_t locus = lexer.peek_token ()->get_locus ();
     641              : 
     642          924 :   bool has_ref = false;
     643         1848 :   if (lexer.peek_token ()->get_id () == REF)
     644              :     {
     645            6 :       has_ref = true;
     646            6 :       lexer.skip_token ();
     647              : 
     648              :       // DEBUG
     649            6 :       rust_debug ("parsed ref in identifier pattern");
     650              :     }
     651              : 
     652          924 :   bool has_mut = false;
     653         1848 :   if (lexer.peek_token ()->get_id () == MUT)
     654              :     {
     655          922 :       has_mut = true;
     656          922 :       lexer.skip_token ();
     657              :     }
     658              : 
     659              :   // parse identifier (required)
     660          924 :   const_TokenPtr ident_tok = expect_token (IDENTIFIER);
     661          924 :   if (ident_tok == nullptr)
     662              :     {
     663              :       // skip somewhere?
     664            0 :       return nullptr;
     665              :     }
     666          924 :   Identifier ident{ident_tok};
     667              : 
     668              :   // DEBUG
     669          924 :   rust_debug ("parsed identifier in identifier pattern");
     670              : 
     671              :   // parse optional pattern binding thing
     672          924 :   std::unique_ptr<AST::Pattern> bind_pattern = nullptr;
     673         1848 :   if (lexer.peek_token ()->get_id () == PATTERN_BIND)
     674              :     {
     675            1 :       lexer.skip_token ();
     676              : 
     677              :       // parse required pattern to bind
     678            1 :       bind_pattern = parse_pattern_no_alt ();
     679            1 :       if (bind_pattern == nullptr)
     680              :         {
     681            0 :           Error error (lexer.peek_token ()->get_locus (),
     682              :                        "failed to parse pattern to bind in identifier pattern");
     683            0 :           add_error (std::move (error));
     684              : 
     685            0 :           return nullptr;
     686            0 :         }
     687              :     }
     688              : 
     689              :   // DEBUG
     690          924 :   rust_debug ("about to return identifier pattern");
     691              : 
     692              :   return std::unique_ptr<AST::IdentifierPattern> (
     693          924 :     new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut,
     694          924 :                                 std::move (bind_pattern)));
     695          924 : }
     696              : 
     697              : /* Parses a pattern that opens with an identifier. This includes identifier
     698              :  * patterns, path patterns (and derivatives such as struct patterns, tuple
     699              :  * struct patterns, and macro invocations), and ranges. */
     700              : template <typename ManagedTokenSource>
     701              : std::unique_ptr<AST::Pattern>
     702        25117 : Parser<ManagedTokenSource>::parse_ident_leading_pattern ()
     703              : {
     704              :   // ensure first token is actually identifier
     705        25117 :   const_TokenPtr initial_tok = lexer.peek_token ();
     706        25117 :   if (initial_tok->get_id () != IDENTIFIER)
     707              :     {
     708            0 :       return nullptr;
     709              :     }
     710              : 
     711              :   // save initial identifier as it may be useful (but don't skip)
     712        25117 :   std::string initial_ident = initial_tok->get_str ();
     713              : 
     714              :   // parse next tokens as a PathInExpression
     715        25117 :   AST::PathInExpression path = parse_path_in_expression ();
     716              : 
     717              :   // branch on next token
     718        25117 :   const_TokenPtr t = lexer.peek_token ();
     719        25117 :   switch (t->get_id ())
     720              :     {
     721            3 :     case EXCLAM:
     722            6 :       return parse_macro_invocation_partial (std::move (path), AST::AttrVec ());
     723          924 :     case LEFT_PAREN:
     724              :       {
     725              :         // tuple struct
     726          924 :         lexer.skip_token ();
     727              : 
     728              :         // DEBUG
     729          924 :         rust_debug ("parsing tuple struct pattern");
     730              : 
     731              :         // parse items
     732          924 :         std::unique_ptr<AST::TupleStructItems> items
     733              :           = parse_tuple_struct_items ();
     734          924 :         if (items == nullptr)
     735              :           {
     736            1 :             Error error (lexer.peek_token ()->get_locus (),
     737              :                          "failed to parse tuple struct items");
     738            1 :             add_error (std::move (error));
     739              : 
     740            1 :             return nullptr;
     741            1 :           }
     742              : 
     743              :         // DEBUG
     744          923 :         rust_debug ("successfully parsed tuple struct items");
     745              : 
     746          923 :         if (!skip_token (RIGHT_PAREN))
     747              :           {
     748            0 :             return nullptr;
     749              :           }
     750              : 
     751              :         // DEBUG
     752          923 :         rust_debug ("successfully parsed tuple struct pattern");
     753              : 
     754          923 :         return std::unique_ptr<AST::TupleStructPattern> (
     755          923 :           new AST::TupleStructPattern (std::move (path), std::move (items)));
     756          924 :       }
     757          110 :     case LEFT_CURLY:
     758              :       {
     759              :         // struct
     760          110 :         lexer.skip_token ();
     761              : 
     762              :         // parse elements (optional)
     763          110 :         AST::StructPatternElements elems = parse_struct_pattern_elems ();
     764              : 
     765          110 :         if (!skip_token (RIGHT_CURLY))
     766              :           {
     767            0 :             return nullptr;
     768              :           }
     769              : 
     770              :         // DEBUG
     771          110 :         rust_debug ("successfully parsed struct pattern");
     772              : 
     773          110 :         return std::unique_ptr<AST::StructPattern> (
     774          220 :           new AST::StructPattern (std::move (path), initial_tok->get_locus (),
     775          110 :                                   std::move (elems)));
     776          110 :       }
     777            8 :     case DOT_DOT_EQ:
     778              :     case DOT_DOT:
     779              :     case ELLIPSIS:
     780              :       {
     781              :         // range
     782              :         AST::RangeKind kind
     783            8 :           = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ());
     784              : 
     785            8 :         lexer.skip_token ();
     786              : 
     787            8 :         std::unique_ptr<AST::RangePatternBoundPath> lower_bound (
     788            8 :           new AST::RangePatternBoundPath (std::move (path)));
     789            8 :         std::unique_ptr<AST::RangePatternBound> upper_bound
     790              :           = parse_range_pattern_bound ();
     791              : 
     792            8 :         return std::unique_ptr<AST::RangePattern> (
     793            8 :           new AST::RangePattern (std::move (lower_bound),
     794              :                                  std::move (upper_bound), kind,
     795            8 :                                  t->get_locus ()));
     796            8 :       }
     797           18 :     case PATTERN_BIND:
     798              :       {
     799              :         // only allow on single-segment paths
     800           18 :         if (path.is_single_segment ())
     801              :           {
     802              :             // identifier with pattern bind
     803           18 :             lexer.skip_token ();
     804              : 
     805           18 :             std::unique_ptr<AST::Pattern> bind_pattern
     806              :               = parse_pattern_no_alt ();
     807           18 :             if (bind_pattern == nullptr)
     808              :               {
     809            1 :                 Error error (
     810              :                   t->get_locus (),
     811              :                   "failed to parse pattern to bind to identifier pattern");
     812            1 :                 add_error (std::move (error));
     813              : 
     814            1 :                 return nullptr;
     815            1 :               }
     816           17 :             return std::unique_ptr<AST::IdentifierPattern> (
     817           51 :               new AST::IdentifierPattern (std::move (initial_ident),
     818              :                                           initial_tok->get_locus (), false,
     819           17 :                                           false, std::move (bind_pattern)));
     820           18 :           }
     821            0 :         Error error (
     822              :           t->get_locus (),
     823              :           "failed to parse pattern bind to a path, not an identifier");
     824            0 :         add_error (std::move (error));
     825              : 
     826            0 :         return nullptr;
     827            0 :       }
     828        24054 :     default:
     829              :       // assume identifier if single segment
     830        24054 :       if (path.is_single_segment ())
     831              :         {
     832        23079 :           return std::unique_ptr<AST::IdentifierPattern> (
     833        69237 :             new AST::IdentifierPattern (std::move (initial_ident),
     834        23079 :                                         initial_tok->get_locus ()));
     835              :         }
     836              :       // return path otherwise
     837          975 :       return std::unique_ptr<AST::PathInExpression> (
     838          975 :         new AST::PathInExpression (std::move (path)));
     839              :     }
     840        25117 : }
     841              : 
     842              : // Parses struct pattern elements if they exist.
     843              : template <typename ManagedTokenSource>
     844              : AST::StructPatternElements
     845          110 : Parser<ManagedTokenSource>::parse_struct_pattern_elems ()
     846              : {
     847          110 :   std::vector<std::unique_ptr<AST::StructPatternField>> fields;
     848              : 
     849          110 :   AST::AttrVec etc_attrs;
     850          110 :   bool has_rest = false;
     851              : 
     852              :   // try parsing struct pattern fields
     853          110 :   const_TokenPtr t = lexer.peek_token ();
     854          370 :   while (t->get_id () != RIGHT_CURLY)
     855              :     {
     856          178 :       AST::AttrVec outer_attrs = parse_outer_attributes ();
     857              : 
     858              :       // parse etc (must be last in struct pattern, so breaks)
     859          356 :       if (lexer.peek_token ()->get_id () == DOT_DOT)
     860              :         {
     861            5 :           lexer.skip_token ();
     862            5 :           etc_attrs = std::move (outer_attrs);
     863            5 :           has_rest = true;
     864            5 :           break;
     865              :         }
     866              : 
     867          173 :       std::unique_ptr<AST::StructPatternField> field
     868          173 :         = parse_struct_pattern_field_partial (std::move (outer_attrs));
     869          173 :       if (field == nullptr)
     870              :         {
     871            0 :           Error error (lexer.peek_token ()->get_locus (),
     872              :                        "failed to parse struct pattern field");
     873            0 :           add_error (std::move (error));
     874              : 
     875              :           // skip after somewhere?
     876            0 :           return AST::StructPatternElements::create_empty ();
     877            0 :         }
     878          173 :       fields.push_back (std::move (field));
     879              : 
     880          346 :       if (lexer.peek_token ()->get_id () != COMMA)
     881              :         break;
     882              : 
     883              :       // skip comma
     884           82 :       lexer.skip_token ();
     885           82 :       t = lexer.peek_token ();
     886              :     }
     887              : 
     888          110 :   if (has_rest)
     889            5 :     return AST::StructPatternElements (std::move (fields),
     890              :                                        std::move (etc_attrs));
     891              :   else
     892          105 :     return AST::StructPatternElements (std::move (fields));
     893          110 : }
     894              : 
     895              : /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
     896              :  * identifier). */
     897              : template <typename ManagedTokenSource>
     898              : std::unique_ptr<AST::StructPatternField>
     899            0 : Parser<ManagedTokenSource>::parse_struct_pattern_field ()
     900              : {
     901              :   // parse outer attributes (if they exist)
     902            0 :   AST::AttrVec outer_attrs = parse_outer_attributes ();
     903              : 
     904            0 :   return parse_struct_pattern_field_partial (std::move (outer_attrs));
     905            0 : }
     906              : 
     907              : /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or
     908              :  * identifier), with outer attributes passed in. */
     909              : template <typename ManagedTokenSource>
     910              : std::unique_ptr<AST::StructPatternField>
     911          173 : Parser<ManagedTokenSource>::parse_struct_pattern_field_partial (
     912              :   AST::AttrVec outer_attrs)
     913              : {
     914              :   // branch based on next token
     915          173 :   const_TokenPtr t = lexer.peek_token ();
     916          173 :   switch (t->get_id ())
     917              :     {
     918           26 :     case INT_LITERAL:
     919              :       {
     920              :         // tuple index
     921           52 :         std::string index_str = t->get_str ();
     922           26 :         int index = atoi (index_str.c_str ());
     923              : 
     924           26 :         lexer.skip_token ();
     925              : 
     926           26 :         if (!skip_token (COLON))
     927              :           {
     928            0 :             return nullptr;
     929              :           }
     930              : 
     931              :         // parse required pattern
     932           26 :         std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
     933           26 :         if (pattern == nullptr)
     934              :           {
     935            0 :             Error error (
     936              :               t->get_locus (),
     937              :               "failed to parse pattern in tuple index struct pattern field");
     938            0 :             add_error (std::move (error));
     939              : 
     940            0 :             return nullptr;
     941            0 :           }
     942              : 
     943           26 :         return std::unique_ptr<AST::StructPatternFieldTuplePat> (
     944           26 :           new AST::StructPatternFieldTuplePat (index, std::move (pattern),
     945              :                                                std::move (outer_attrs),
     946           26 :                                                t->get_locus ()));
     947           52 :       }
     948          145 :     case IDENTIFIER:
     949              :       // identifier-pattern OR only identifier
     950              :       // branch on next token
     951          290 :       switch (lexer.peek_token (1)->get_id ())
     952              :         {
     953           59 :         case COLON:
     954              :           {
     955              :             // identifier-pattern
     956           59 :             Identifier ident{t};
     957           59 :             lexer.skip_token ();
     958              : 
     959           59 :             skip_token (COLON);
     960              : 
     961              :             // parse required pattern
     962           59 :             std::unique_ptr<AST::Pattern> pattern = parse_pattern ();
     963           59 :             if (pattern == nullptr)
     964              :               {
     965            0 :                 Error error (t->get_locus (),
     966              :                              "failed to parse pattern in struct pattern field");
     967            0 :                 add_error (std::move (error));
     968              : 
     969            0 :                 return nullptr;
     970            0 :               }
     971              : 
     972           59 :             return std::unique_ptr<AST::StructPatternFieldIdentPat> (
     973          118 :               new AST::StructPatternFieldIdentPat (std::move (ident),
     974              :                                                    std::move (pattern),
     975              :                                                    std::move (outer_attrs),
     976           59 :                                                    t->get_locus ()));
     977           59 :           }
     978           86 :         case COMMA:
     979              :         case RIGHT_CURLY:
     980              :           {
     981              :             // identifier only
     982           86 :             Identifier ident = {t};
     983           86 :             lexer.skip_token ();
     984              : 
     985           86 :             return std::unique_ptr<AST::StructPatternFieldIdent> (
     986          172 :               new AST::StructPatternFieldIdent (std::move (ident), false, false,
     987              :                                                 std::move (outer_attrs),
     988           86 :                                                 t->get_locus ()));
     989           86 :           }
     990            0 :         default:
     991              :           // error
     992            0 :           add_error (Error (t->get_locus (),
     993              :                             "unrecognised token %qs in struct pattern field",
     994              :                             t->get_token_description ()));
     995              : 
     996            0 :           return nullptr;
     997              :         }
     998            2 :     case REF:
     999              :     case MUT:
    1000              :       {
    1001              :         // only identifier
    1002            2 :         bool has_ref = false;
    1003            2 :         if (t->get_id () == REF)
    1004              :           {
    1005            0 :             has_ref = true;
    1006            0 :             lexer.skip_token ();
    1007              :           }
    1008              : 
    1009            2 :         bool has_mut = false;
    1010            4 :         if (lexer.peek_token ()->get_id () == MUT)
    1011              :           {
    1012            2 :             has_mut = true;
    1013            2 :             lexer.skip_token ();
    1014              :           }
    1015              : 
    1016            2 :         const_TokenPtr ident_tok = expect_token (IDENTIFIER);
    1017            2 :         if (ident_tok == nullptr)
    1018              :           {
    1019            0 :             return nullptr;
    1020              :           }
    1021            2 :         Identifier ident{ident_tok};
    1022              : 
    1023            2 :         return std::unique_ptr<AST::StructPatternFieldIdent> (
    1024            4 :           new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut,
    1025              :                                             std::move (outer_attrs),
    1026            2 :                                             t->get_locus ()));
    1027            4 :       }
    1028            0 :     default:
    1029              :       // not necessarily an error
    1030            0 :       return nullptr;
    1031              :     }
    1032          173 : }
    1033              : 
    1034              : /* Parses a literal pattern or range pattern. Assumes that literals passed in
    1035              :  * are valid range pattern bounds. Do not pass in paths in expressions, for
    1036              :  * instance. */
    1037              : template <typename ManagedTokenSource>
    1038              : std::unique_ptr<AST::Pattern>
    1039          483 : Parser<ManagedTokenSource>::parse_literal_or_range_pattern ()
    1040              : {
    1041          483 :   const_TokenPtr range_lower = lexer.peek_token ();
    1042          483 :   AST::Literal::LitType type = AST::Literal::STRING;
    1043          483 :   bool has_minus = false;
    1044              : 
    1045              :   // get lit type
    1046          483 :   switch (range_lower->get_id ())
    1047              :     {
    1048           28 :     case CHAR_LITERAL:
    1049           28 :       type = AST::Literal::CHAR;
    1050           28 :       lexer.skip_token ();
    1051              :       break;
    1052           21 :     case BYTE_CHAR_LITERAL:
    1053           21 :       type = AST::Literal::BYTE;
    1054           21 :       lexer.skip_token ();
    1055              :       break;
    1056          406 :     case INT_LITERAL:
    1057          406 :       type = AST::Literal::INT;
    1058          406 :       lexer.skip_token ();
    1059              :       break;
    1060            2 :     case FLOAT_LITERAL:
    1061            2 :       type = AST::Literal::FLOAT;
    1062            2 :       lexer.skip_token ();
    1063              :       break;
    1064           26 :     case MINUS:
    1065              :       // branch on next token
    1066           52 :       range_lower = lexer.peek_token (1);
    1067           26 :       switch (range_lower->get_id ())
    1068              :         {
    1069           24 :         case INT_LITERAL:
    1070           24 :           type = AST::Literal::INT;
    1071           24 :           has_minus = true;
    1072           24 :           lexer.skip_token (1);
    1073           24 :           break;
    1074            2 :         case FLOAT_LITERAL:
    1075            2 :           type = AST::Literal::FLOAT;
    1076            2 :           has_minus = true;
    1077            2 :           lexer.skip_token (1);
    1078            2 :           break;
    1079            0 :         default:
    1080            0 :           add_error (Error (range_lower->get_locus (),
    1081              :                             "token type %qs cannot be parsed as range pattern "
    1082              :                             "bound or literal after minus symbol",
    1083              :                             range_lower->get_token_description ()));
    1084              : 
    1085            0 :           return nullptr;
    1086              :         }
    1087              :       break;
    1088            0 :     default:
    1089            0 :       add_error (
    1090            0 :         Error (range_lower->get_locus (),
    1091              :                "token type %qs cannot be parsed as range pattern bound",
    1092              :                range_lower->get_token_description ()));
    1093              : 
    1094            0 :       return nullptr;
    1095              :     }
    1096              : 
    1097          483 :   const_TokenPtr next = lexer.peek_token ();
    1098          483 :   if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS
    1099          942 :       || next->get_id () == DOT_DOT)
    1100              :     {
    1101           48 :       AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ());
    1102              :       // range pattern
    1103           48 :       lexer.skip_token ();
    1104           48 :       std::unique_ptr<AST::RangePatternBound> lower (
    1105           96 :         new AST::RangePatternBoundLiteral (
    1106          144 :           AST::Literal (range_lower->get_str (), type,
    1107              :                         PrimitiveCoreType::CORETYPE_UNKNOWN),
    1108              :           range_lower->get_locus (), has_minus));
    1109              : 
    1110           48 :       std::unique_ptr<AST::RangePatternBound> upper
    1111              :         = parse_range_pattern_bound ();
    1112           48 :       if (upper == nullptr)
    1113              :         {
    1114            0 :           Error error (next->get_locus (),
    1115              :                        "failed to parse range pattern bound in range pattern");
    1116            0 :           add_error (std::move (error));
    1117              : 
    1118            0 :           return nullptr;
    1119            0 :         }
    1120              : 
    1121           48 :       return std::unique_ptr<AST::RangePattern> (
    1122           48 :         new AST::RangePattern (std::move (lower), std::move (upper), kind,
    1123           48 :                                range_lower->get_locus ()));
    1124           48 :     }
    1125              :   else
    1126              :     {
    1127              :       // literal pattern
    1128          435 :       return std::unique_ptr<AST::LiteralPattern> (
    1129         1353 :         new AST::LiteralPattern (range_lower->get_str (), type,
    1130              :                                  range_lower->get_locus (),
    1131          435 :                                  range_lower->get_type_hint (), has_minus));
    1132              :     }
    1133          483 : }
    1134              : 
    1135              : // Parses a range pattern bound (value only).
    1136              : template <typename ManagedTokenSource>
    1137              : std::unique_ptr<AST::RangePatternBound>
    1138           56 : Parser<ManagedTokenSource>::parse_range_pattern_bound ()
    1139              : {
    1140           56 :   const_TokenPtr range_lower = lexer.peek_token ();
    1141           56 :   location_t range_lower_locus = range_lower->get_locus ();
    1142              : 
    1143              :   // get lit type
    1144           56 :   switch (range_lower->get_id ())
    1145              :     {
    1146            7 :     case CHAR_LITERAL:
    1147            7 :       lexer.skip_token ();
    1148            7 :       return std::unique_ptr<AST::RangePatternBoundLiteral> (
    1149           14 :         new AST::RangePatternBoundLiteral (
    1150           28 :           AST::Literal (range_lower->get_str (), AST::Literal::CHAR,
    1151              :                         range_lower->get_type_hint ()),
    1152            7 :           range_lower_locus));
    1153            0 :     case BYTE_CHAR_LITERAL:
    1154            0 :       lexer.skip_token ();
    1155            0 :       return std::unique_ptr<AST::RangePatternBoundLiteral> (
    1156            0 :         new AST::RangePatternBoundLiteral (
    1157            0 :           AST::Literal (range_lower->get_str (), AST::Literal::BYTE,
    1158              :                         range_lower->get_type_hint ()),
    1159            0 :           range_lower_locus));
    1160           22 :     case INT_LITERAL:
    1161           22 :       lexer.skip_token ();
    1162           22 :       return std::unique_ptr<AST::RangePatternBoundLiteral> (
    1163           44 :         new AST::RangePatternBoundLiteral (
    1164           76 :           AST::Literal (range_lower->get_str (), AST::Literal::INT,
    1165              :                         range_lower->get_type_hint ()),
    1166           22 :           range_lower_locus));
    1167            0 :     case FLOAT_LITERAL:
    1168            0 :       lexer.skip_token ();
    1169            0 :       rust_debug ("warning: used deprecated float range pattern bound");
    1170            0 :       return std::unique_ptr<AST::RangePatternBoundLiteral> (
    1171            0 :         new AST::RangePatternBoundLiteral (
    1172            0 :           AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
    1173              :                         range_lower->get_type_hint ()),
    1174            0 :           range_lower_locus));
    1175           12 :     case MINUS:
    1176              :       // branch on next token
    1177           12 :       range_lower = lexer.peek_token (1);
    1178           12 :       switch (range_lower->get_id ())
    1179              :         {
    1180           10 :         case INT_LITERAL:
    1181           10 :           lexer.skip_token (1);
    1182           10 :           return std::unique_ptr<AST::RangePatternBoundLiteral> (
    1183           20 :             new AST::RangePatternBoundLiteral (
    1184           30 :               AST::Literal (range_lower->get_str (), AST::Literal::INT,
    1185              :                             range_lower->get_type_hint ()),
    1186           10 :               range_lower_locus, true));
    1187            2 :         case FLOAT_LITERAL:
    1188            2 :           lexer.skip_token (1);
    1189            2 :           rust_debug ("warning: used deprecated float range pattern bound");
    1190            2 :           return std::unique_ptr<AST::RangePatternBoundLiteral> (
    1191            4 :             new AST::RangePatternBoundLiteral (
    1192            8 :               AST::Literal (range_lower->get_str (), AST::Literal::FLOAT,
    1193              :                             range_lower->get_type_hint ()),
    1194            2 :               range_lower_locus, true));
    1195            0 :         default:
    1196            0 :           add_error (Error (range_lower->get_locus (),
    1197              :                             "token type %qs cannot be parsed as range pattern "
    1198              :                             "bound after minus symbol",
    1199              :                             range_lower->get_token_description ()));
    1200              : 
    1201            0 :           return nullptr;
    1202              :         }
    1203           15 :     case IDENTIFIER:
    1204              :     case SUPER:
    1205              :     case SELF:
    1206              :     case SELF_ALIAS:
    1207              :     case CRATE:
    1208              :     case SCOPE_RESOLUTION:
    1209              :     case DOLLAR_SIGN:
    1210              :       {
    1211              :         // path in expression
    1212           15 :         AST::PathInExpression path = parse_path_in_expression ();
    1213           15 :         if (path.is_error ())
    1214              :           {
    1215            0 :             Error error (
    1216              :               range_lower->get_locus (),
    1217              :               "failed to parse path in expression range pattern bound");
    1218            0 :             add_error (std::move (error));
    1219              : 
    1220            0 :             return nullptr;
    1221            0 :           }
    1222           15 :         return std::unique_ptr<AST::RangePatternBoundPath> (
    1223           15 :           new AST::RangePatternBoundPath (std::move (path)));
    1224           15 :       }
    1225            0 :     case LEFT_SHIFT:
    1226              :     case LEFT_ANGLE:
    1227              :       {
    1228              :         // qualified path in expression
    1229            0 :         AST::QualifiedPathInExpression path
    1230              :           = parse_qualified_path_in_expression ();
    1231            0 :         if (path.is_error ())
    1232              :           {
    1233            0 :             Error error (range_lower->get_locus (),
    1234              :                          "failed to parse qualified path in expression range "
    1235              :                          "pattern bound");
    1236            0 :             add_error (std::move (error));
    1237              : 
    1238            0 :             return nullptr;
    1239            0 :           }
    1240            0 :         return std::unique_ptr<AST::RangePatternBoundQualPath> (
    1241            0 :           new AST::RangePatternBoundQualPath (std::move (path)));
    1242            0 :       }
    1243            0 :     default:
    1244            0 :       add_error (
    1245            0 :         Error (range_lower->get_locus (),
    1246              :                "token type %qs cannot be parsed as range pattern bound",
    1247              :                range_lower->get_token_description ()));
    1248              : 
    1249            0 :       return nullptr;
    1250              :     }
    1251           56 : }
    1252              : 
    1253              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.