LCOV - code coverage report
Current view: top level - gcc/rust/parse - rust-parse-impl-path.hxx (source / functions) Coverage Total Hit
Test: gcc.info Lines: 77.6 % 281 218
Test Date: 2026-02-28 14:20:25 Functions: 95.5 % 22 21
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              : // Parses a SimplePath AST node, if it exists. Does nothing otherwise.
      28              : template <typename ManagedTokenSource>
      29              : tl::expected<AST::SimplePath, Parse::Error::Node>
      30        22644 : Parser<ManagedTokenSource>::parse_simple_path ()
      31              : {
      32        22644 :   bool has_opening_scope_resolution = false;
      33        22644 :   location_t locus = UNKNOWN_LOCATION;
      34              : 
      35              :   using Parse::Utils::is_simple_path_segment;
      36              : 
      37              :   // don't parse anything if not a path upfront
      38        45288 :   if (!is_simple_path_segment (lexer.peek_token ()->get_id ())
      39        22918 :       && !is_simple_path_segment (lexer.peek_token (1)->get_id ()))
      40          220 :     return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::MALFORMED);
      41              : 
      42              :   /* Checks for opening scope resolution (i.e. global scope fully-qualified
      43              :    * path) */
      44        44848 :   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
      45              :     {
      46            0 :       has_opening_scope_resolution = true;
      47              : 
      48            0 :       locus = lexer.peek_token ()->get_locus ();
      49              : 
      50            0 :       lexer.skip_token ();
      51              :     }
      52              : 
      53              :   // Parse single required simple path segment
      54        22424 :   auto segment = parse_simple_path_segment ();
      55              : 
      56        22424 :   if (!segment)
      57           54 :     return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
      58              : 
      59              :   // get location if not gotten already
      60        22370 :   if (locus == UNKNOWN_LOCATION)
      61        22370 :     locus = segment->get_locus ();
      62              : 
      63        22370 :   std::vector<AST::SimplePathSegment> segments;
      64        22370 :   segments.push_back (std::move (segment.value ()));
      65              : 
      66              :   // Parse all other simple path segments
      67        46934 :   while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
      68              :     {
      69         1180 :       auto new_segment = parse_simple_path_segment (1);
      70              : 
      71              :       using Error = Parse::Error::SimplePathSegment::Kind;
      72              :       // Return path as currently constructed if segment in error state.
      73         1180 :       if (!new_segment)
      74              :         {
      75          166 :           if (new_segment.error ().kind == Error::INVALID_SIMPLE_PATH_TOKEN)
      76              :             break; /* Could be end of path */
      77              :           else     /* Any other error is an hard error */
      78              :             return tl::unexpected<Parse::Error::Node> (
      79            0 :               Parse::Error::Node::CHILD_ERROR);
      80              :         }
      81              : 
      82         1014 :       segments.push_back (std::move (new_segment.value ()));
      83              :     }
      84              : 
      85        22370 :   return AST::SimplePath (std::move (segments), has_opening_scope_resolution,
      86        22370 :                           locus);
      87              :   /* TODO: now that is_simple_path_segment exists, could probably start
      88              :    * actually making errors upon parse failure of segments and whatever */
      89        44794 : }
      90              : 
      91              : /* Parses a single SimplePathSegment (does not handle the scope resolution
      92              :  * operators)
      93              :  * Starts parsing at an offset of base_peek */
      94              : template <typename ManagedTokenSource>
      95              : tl::expected<AST::SimplePathSegment, Parse::Error::SimplePathSegment>
      96        23604 : Parser<ManagedTokenSource>::parse_simple_path_segment (int base_peek)
      97              : {
      98              :   using namespace Values;
      99        23604 :   const_TokenPtr t = lexer.peek_token (base_peek);
     100        23604 :   switch (t->get_id ())
     101              :     {
     102        23001 :     case IDENTIFIER:
     103        23001 :       lexer.skip_token (base_peek);
     104              : 
     105        46002 :       return AST::SimplePathSegment (t->get_str (), t->get_locus ());
     106          301 :     case SUPER:
     107          301 :       lexer.skip_token (base_peek);
     108              : 
     109          301 :       return AST::SimplePathSegment (Keywords::SUPER, t->get_locus ());
     110           60 :     case SELF:
     111           60 :       lexer.skip_token (base_peek);
     112              : 
     113           60 :       return AST::SimplePathSegment (Keywords::SELF, t->get_locus ());
     114           22 :     case CRATE:
     115           22 :       lexer.skip_token (base_peek);
     116              : 
     117           22 :       return AST::SimplePathSegment (Keywords::CRATE, t->get_locus ());
     118            0 :     case DOLLAR_SIGN:
     119            0 :       if (lexer.peek_token (base_peek + 1)->get_id () == CRATE)
     120              :         {
     121            0 :           lexer.skip_token (base_peek + 1);
     122              : 
     123            0 :           return AST::SimplePathSegment ("$crate", t->get_locus ());
     124              :         }
     125              :       gcc_fallthrough ();
     126              :     default:
     127              :       // do nothing but inactivates warning from gcc when compiling
     128              :       /* could put the rust_error_at thing here but fallthrough (from failing
     129              :        * $crate condition) isn't completely obvious if it is. */
     130              : 
     131              :       return Parse::Error::SimplePathSegment::make_invalid_token_or_path_end ();
     132              :     }
     133              :   rust_unreachable ();
     134        23604 : }
     135              : 
     136              : // Parses a PathIdentSegment - an identifier segment of a non-SimplePath path.
     137              : template <typename ManagedTokenSource>
     138              : tl::expected<AST::PathIdentSegment, Parse::Error::PathIdentSegment>
     139       139238 : Parser<ManagedTokenSource>::parse_path_ident_segment ()
     140              : {
     141       139238 :   const_TokenPtr t = lexer.peek_token ();
     142       139238 :   switch (t->get_id ())
     143              :     {
     144       123017 :     case IDENTIFIER:
     145       123017 :       lexer.skip_token ();
     146              : 
     147       246034 :       return AST::PathIdentSegment (t->get_str (), t->get_locus ());
     148            8 :     case SUPER:
     149            8 :       lexer.skip_token ();
     150              : 
     151            8 :       return AST::PathIdentSegment (Values::Keywords::SUPER, t->get_locus ());
     152         6904 :     case SELF:
     153         6904 :       lexer.skip_token ();
     154              : 
     155         6904 :       return AST::PathIdentSegment (Values::Keywords::SELF, t->get_locus ());
     156         8431 :     case SELF_ALIAS:
     157         8431 :       lexer.skip_token ();
     158              : 
     159        16862 :       return AST::PathIdentSegment (Values::Keywords::SELF_ALIAS,
     160         8431 :                                     t->get_locus ());
     161          667 :     case CRATE:
     162          667 :       lexer.skip_token ();
     163              : 
     164          667 :       return AST::PathIdentSegment (Values::Keywords::CRATE, t->get_locus ());
     165            4 :     case DOLLAR_SIGN:
     166            8 :       if (lexer.peek_token (1)->get_id () == CRATE)
     167              :         {
     168            0 :           lexer.skip_token (1);
     169              : 
     170            0 :           return AST::PathIdentSegment ("$crate", t->get_locus ());
     171              :         }
     172              :       gcc_fallthrough ();
     173              :     default:
     174              :       /* do nothing but inactivates warning from gcc when compiling
     175              :        * could put the error_at thing here but fallthrough (from failing $crate
     176              :        * condition) isn't completely obvious if it is. */
     177              : 
     178              :       // test prevent error
     179              :       return Parse::Error::PathIdentSegment::make_invalid_token ();
     180              :     }
     181              :   rust_unreachable ();
     182       139238 : }
     183              : 
     184              : // Parses a type path.
     185              : template <typename ManagedTokenSource>
     186              : AST::TypePath
     187        53355 : Parser<ManagedTokenSource>::parse_type_path ()
     188              : {
     189        53355 :   bool has_opening_scope_resolution = false;
     190        53355 :   location_t locus = lexer.peek_token ()->get_locus ();
     191       106710 :   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
     192              :     {
     193           28 :       has_opening_scope_resolution = true;
     194           28 :       lexer.skip_token ();
     195              :     }
     196              : 
     197              :   // create segment vector
     198        53355 :   std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
     199              : 
     200              :   // parse required initial segment
     201        53355 :   std::unique_ptr<AST::TypePathSegment> initial_segment
     202              :     = parse_type_path_segment ();
     203        53355 :   if (initial_segment == nullptr)
     204              :     {
     205              :       // skip after somewhere?
     206              :       // don't necessarily throw error but yeah
     207          203 :       return AST::TypePath::create_error ();
     208              :     }
     209        53152 :   segments.push_back (std::move (initial_segment));
     210              : 
     211              :   // parse optional segments (as long as scope resolution operator exists)
     212        53152 :   const_TokenPtr t = lexer.peek_token ();
     213        54346 :   while (t->get_id () == SCOPE_RESOLUTION)
     214              :     {
     215              :       // skip scope resolution operator
     216         1194 :       lexer.skip_token ();
     217              : 
     218              :       // parse the actual segment - it is an error if it doesn't exist now
     219         1194 :       std::unique_ptr<AST::TypePathSegment> segment
     220              :         = parse_type_path_segment ();
     221         1194 :       if (segment == nullptr)
     222              :         {
     223              :           // skip after somewhere?
     224            0 :           Error error (t->get_locus (), "could not parse type path segment");
     225            0 :           add_error (std::move (error));
     226              : 
     227            0 :           return AST::TypePath::create_error ();
     228            0 :         }
     229              : 
     230         1194 :       segments.push_back (std::move (segment));
     231              : 
     232         1194 :       t = lexer.peek_token ();
     233              :     }
     234              : 
     235        53152 :   segments.shrink_to_fit ();
     236              : 
     237       106304 :   return AST::TypePath (std::move (segments), locus,
     238        53152 :                         has_opening_scope_resolution);
     239        53355 : }
     240              : 
     241              : /* Parses a single type path segment (not including opening scope resolution,
     242              :  * but includes any internal ones). Includes generic args or type path
     243              :  * functions too. */
     244              : template <typename ManagedTokenSource>
     245              : std::unique_ptr<AST::TypePathSegment>
     246        54880 : Parser<ManagedTokenSource>::parse_type_path_segment ()
     247              : {
     248        54880 :   location_t locus = lexer.peek_token ()->get_locus ();
     249              :   // parse ident segment part
     250        54880 :   auto ident_segment_res = parse_path_ident_segment ();
     251        54880 :   if (!ident_segment_res)
     252              :     {
     253              :       // not necessarily an error
     254          203 :       return nullptr;
     255              :     }
     256        54677 :   auto ident_segment = ident_segment_res.value ();
     257              : 
     258              :   /* lookahead to determine if variants exist - only consume scope resolution
     259              :    * then */
     260        54677 :   bool has_separating_scope_resolution = false;
     261        54677 :   const_TokenPtr next = lexer.peek_token (1);
     262       109354 :   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
     263        54677 :       && (next->get_id () == LEFT_ANGLE || next->get_id () == LEFT_PAREN))
     264              :     {
     265            0 :       has_separating_scope_resolution = true;
     266            0 :       lexer.skip_token ();
     267              :     }
     268              : 
     269              :   // branch into variants on next token
     270        54677 :   const_TokenPtr t = lexer.peek_token ();
     271        54677 :   switch (t->get_id ())
     272              :     {
     273         2737 :     case LEFT_SHIFT:
     274              :     case LEFT_ANGLE:
     275              :       {
     276              :         // parse generic args
     277         2737 :         AST::GenericArgs generic_args = parse_path_generic_args ();
     278              : 
     279         2737 :         return std::unique_ptr<AST::TypePathSegmentGeneric> (
     280         5474 :           new AST::TypePathSegmentGeneric (std::move (ident_segment),
     281              :                                            has_separating_scope_resolution,
     282         2737 :                                            std::move (generic_args), locus));
     283         2737 :       }
     284           30 :     case LEFT_PAREN:
     285              :       {
     286              :         // parse type path function
     287           30 :         AST::TypePathFunction type_path_function
     288              :           = parse_type_path_function (locus);
     289              : 
     290           30 :         if (type_path_function.is_error ())
     291              :           {
     292              :             // skip after somewhere?
     293            0 :             return nullptr;
     294              :           }
     295              : 
     296           30 :         return std::unique_ptr<AST::TypePathSegmentFunction> (
     297           90 :           new AST::TypePathSegmentFunction (std::move (ident_segment),
     298              :                                             has_separating_scope_resolution,
     299              :                                             std::move (type_path_function),
     300           30 :                                             locus));
     301           30 :       }
     302        51910 :     default:
     303              :       // neither of them
     304              :       return std::unique_ptr<AST::TypePathSegment> (
     305        51910 :         new AST::TypePathSegment (std::move (ident_segment),
     306        51910 :                                   has_separating_scope_resolution, locus));
     307              :     }
     308              :   rust_unreachable ();
     309       109354 : }
     310              : 
     311              : // Parses a function call representation inside a type path.
     312              : template <typename ManagedTokenSource>
     313              : AST::TypePathFunction
     314           30 : Parser<ManagedTokenSource>::parse_type_path_function (location_t id_location)
     315              : {
     316           30 :   if (!skip_token (LEFT_PAREN))
     317              :     {
     318              :       // skip somewhere?
     319              :       return AST::TypePathFunction::create_error ();
     320              :     }
     321              : 
     322              :   // parse function inputs
     323           30 :   std::vector<std::unique_ptr<AST::Type>> inputs;
     324              : 
     325           94 :   while (lexer.peek_token ()->get_id () != RIGHT_PAREN)
     326              :     {
     327           32 :       std::unique_ptr<AST::Type> type = parse_type ();
     328           32 :       if (type == nullptr)
     329              :         {
     330              :           /* this is an error as there should've been a ')' there if there
     331              :            * wasn't a type */
     332            0 :           Error error (
     333            0 :             lexer.peek_token ()->get_locus (),
     334              :             "failed to parse type in parameters of type path function");
     335            0 :           add_error (std::move (error));
     336              : 
     337              :           // skip somewhere?
     338            0 :           return AST::TypePathFunction::create_error ();
     339            0 :         }
     340              : 
     341           32 :       inputs.push_back (std::move (type));
     342              : 
     343              :       // skip commas, including trailing commas
     344           64 :       if (lexer.peek_token ()->get_id () != COMMA)
     345              :         break;
     346              : 
     347            2 :       lexer.skip_token ();
     348              :     }
     349              : 
     350           30 :   if (!skip_token (RIGHT_PAREN))
     351              :     {
     352              :       // skip somewhere?
     353              :       return AST::TypePathFunction::create_error ();
     354              :     }
     355              : 
     356              :   // parse optional return type
     357           30 :   std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
     358              : 
     359           30 :   inputs.shrink_to_fit ();
     360           30 :   return AST::TypePathFunction (std::move (inputs), id_location,
     361           30 :                                 std::move (return_type));
     362           30 : }
     363              : 
     364              : // Parses a path inside an expression that allows generic arguments.
     365              : template <typename ManagedTokenSource>
     366              : AST::PathInExpression
     367        73330 : Parser<ManagedTokenSource>::parse_path_in_expression ()
     368              : {
     369        73330 :   location_t locus = UNKNOWN_LOCATION;
     370        73330 :   bool has_opening_scope_resolution = false;
     371       146660 :   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
     372              :     {
     373            9 :       has_opening_scope_resolution = true;
     374              : 
     375            9 :       locus = lexer.peek_token ()->get_locus ();
     376              : 
     377            9 :       lexer.skip_token ();
     378              :     }
     379              : 
     380              :   // create segment vector
     381        73330 :   std::vector<AST::PathExprSegment> segments;
     382              : 
     383        73330 :   if (locus == UNKNOWN_LOCATION)
     384              :     {
     385       146642 :       locus = lexer.peek_token ()->get_locus ();
     386              :     }
     387              : 
     388              :   // parse required initial segment
     389        73330 :   AST::PathExprSegment initial_segment = parse_path_expr_segment ();
     390        73330 :   if (initial_segment.is_error ())
     391              :     {
     392              :       // skip after somewhere?
     393              :       // don't necessarily throw error but yeah
     394            4 :       return AST::PathInExpression::create_error ();
     395              :     }
     396        73326 :   segments.push_back (std::move (initial_segment));
     397              : 
     398              :   // parse optional segments (as long as scope resolution operator exists)
     399        73326 :   const_TokenPtr t = lexer.peek_token ();
     400        81237 :   while (t->get_id () == SCOPE_RESOLUTION)
     401              :     {
     402              :       // skip scope resolution operator
     403         7911 :       lexer.skip_token ();
     404              : 
     405              :       // parse the actual segment - it is an error if it doesn't exist now
     406         7911 :       AST::PathExprSegment segment = parse_path_expr_segment ();
     407         7911 :       if (segment.is_error ())
     408              :         {
     409              :           // skip after somewhere?
     410            4 :           Error error (t->get_locus (),
     411              :                        "could not parse path expression segment");
     412            4 :           add_error (std::move (error));
     413              : 
     414            4 :           return AST::PathInExpression::create_error ();
     415            4 :         }
     416              : 
     417         7907 :       segments.push_back (std::move (segment));
     418              : 
     419         7907 :       t = lexer.peek_token ();
     420              :     }
     421              : 
     422        73322 :   segments.shrink_to_fit ();
     423              : 
     424        73322 :   return AST::PathInExpression (std::move (segments), {}, locus,
     425        73322 :                                 has_opening_scope_resolution);
     426       146656 : }
     427              : 
     428              : /* Parses a single path in expression path segment (including generic
     429              :  * arguments). */
     430              : template <typename ManagedTokenSource>
     431              : AST::PathExprSegment
     432        84358 : Parser<ManagedTokenSource>::parse_path_expr_segment ()
     433              : {
     434        84358 :   location_t locus = lexer.peek_token ()->get_locus ();
     435              :   // parse ident segment
     436        84358 :   auto ident_result = parse_path_ident_segment ();
     437        84358 :   if (!ident_result)
     438              :     {
     439              :       // not necessarily an error?
     440            8 :       return AST::PathExprSegment::create_error ();
     441              :     }
     442        84350 :   auto ident = ident_result.value ();
     443              : 
     444              :   // parse generic args (and turbofish), if they exist
     445              :   /* use lookahead to determine if they actually exist (don't want to
     446              :    * accidently parse over next ident segment) */
     447       168700 :   if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
     448       114415 :       && (lexer.peek_token (1)->get_id () == LEFT_ANGLE
     449        31770 :           || lexer.peek_token (1)->get_id () == LEFT_SHIFT))
     450              :     {
     451              :       // skip scope resolution
     452          906 :       lexer.skip_token ();
     453              : 
     454              :       // Let parse_path_generic_args split "<<" tokens
     455          906 :       AST::GenericArgs generic_args = parse_path_generic_args ();
     456              : 
     457         1812 :       return AST::PathExprSegment (std::move (ident), locus,
     458          906 :                                    std::move (generic_args));
     459          906 :     }
     460              : 
     461              :   // return a generic parameter-less expr segment if not found
     462        83444 :   return AST::PathExprSegment (std::move (ident), locus);
     463        84350 : }
     464              : 
     465              : /* Parses a fully qualified path in expression (i.e. a pattern). FIXME does
     466              :  * not parse outer attrs. */
     467              : template <typename ManagedTokenSource>
     468              : AST::QualifiedPathInExpression
     469           97 : Parser<ManagedTokenSource>::parse_qualified_path_in_expression (
     470              :   location_t pratt_parsed_loc)
     471              : {
     472              :   /* Note: the Rust grammar is defined in such a way that it is impossible to
     473              :    * determine whether a prospective qualified path is a
     474              :    * QualifiedPathInExpression or QualifiedPathInType in all cases by the
     475              :    * rules themselves (the only possible difference is a TypePathSegment with
     476              :    * function, and lookahead to find this is too difficult). However, as this
     477              :    * is a pattern and QualifiedPathInType is a type, I believe it that their
     478              :    * construction will not be confused (due to rules regarding patterns vs
     479              :    * types).
     480              :    * As such, this function will not attempt to minimise errors created by
     481              :    * their confusion. */
     482              : 
     483              :   // parse the qualified path type (required)
     484           97 :   AST::QualifiedPathType qual_path_type
     485              :     = parse_qualified_path_type (pratt_parsed_loc);
     486           97 :   if (qual_path_type.is_error ())
     487              :     {
     488              :       // TODO: should this create a parse error?
     489            0 :       return AST::QualifiedPathInExpression::create_error ();
     490              :     }
     491           97 :   location_t locus = qual_path_type.get_locus ();
     492              : 
     493              :   // parse path segments
     494           97 :   std::vector<AST::PathExprSegment> segments;
     495              : 
     496              :   // parse initial required segment
     497          194 :   if (!expect_token (SCOPE_RESOLUTION))
     498              :     {
     499              :       // skip after somewhere?
     500              : 
     501            0 :       return AST::QualifiedPathInExpression::create_error ();
     502              :     }
     503           97 :   AST::PathExprSegment initial_segment = parse_path_expr_segment ();
     504           97 :   if (initial_segment.is_error ())
     505              :     {
     506              :       // skip after somewhere?
     507            0 :       Error error (lexer.peek_token ()->get_locus (),
     508              :                    "required initial path expression segment in "
     509              :                    "qualified path in expression could not be parsed");
     510            0 :       add_error (std::move (error));
     511              : 
     512            0 :       return AST::QualifiedPathInExpression::create_error ();
     513            0 :     }
     514           97 :   segments.push_back (std::move (initial_segment));
     515              : 
     516              :   // parse optional segments (as long as scope resolution operator exists)
     517           97 :   const_TokenPtr t = lexer.peek_token ();
     518           97 :   while (t->get_id () == SCOPE_RESOLUTION)
     519              :     {
     520              :       // skip scope resolution operator
     521            0 :       lexer.skip_token ();
     522              : 
     523              :       // parse the actual segment - it is an error if it doesn't exist now
     524            0 :       AST::PathExprSegment segment = parse_path_expr_segment ();
     525            0 :       if (segment.is_error ())
     526              :         {
     527              :           // skip after somewhere?
     528            0 :           Error error (t->get_locus (),
     529              :                        "could not parse path expression segment in qualified "
     530              :                        "path in expression");
     531            0 :           add_error (std::move (error));
     532              : 
     533            0 :           return AST::QualifiedPathInExpression::create_error ();
     534            0 :         }
     535              : 
     536            0 :       segments.push_back (std::move (segment));
     537              : 
     538            0 :       t = lexer.peek_token ();
     539              :     }
     540              : 
     541           97 :   segments.shrink_to_fit ();
     542              : 
     543              :   // FIXME: outer attr parsing
     544          194 :   return AST::QualifiedPathInExpression (std::move (qual_path_type),
     545           97 :                                          std::move (segments), {}, locus);
     546          194 : }
     547              : 
     548              : // Parses the type syntactical construction at the start of a qualified path.
     549              : template <typename ManagedTokenSource>
     550              : AST::QualifiedPathType
     551          428 : Parser<ManagedTokenSource>::parse_qualified_path_type (
     552              :   location_t pratt_parsed_loc)
     553              : {
     554          428 :   location_t locus = pratt_parsed_loc;
     555              :   /* TODO: should this actually be error? is there anywhere where this could
     556              :    * be valid? */
     557          428 :   if (locus == UNKNOWN_LOCATION)
     558              :     {
     559          331 :       locus = lexer.peek_token ()->get_locus ();
     560              : 
     561          662 :       if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
     562            1 :         lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
     563              : 
     564              :       // skip after somewhere?
     565          331 :       if (!skip_token (LEFT_ANGLE))
     566            0 :         return AST::QualifiedPathType::create_error ();
     567              :     }
     568              : 
     569              :   // parse type (required)
     570          428 :   std::unique_ptr<AST::Type> type = parse_type ();
     571          428 :   if (type == nullptr)
     572              :     {
     573            0 :       Error error (lexer.peek_token ()->get_locus (),
     574              :                    "could not parse type in qualified path type");
     575            0 :       add_error (std::move (error));
     576              : 
     577              :       // skip somewhere?
     578            0 :       return AST::QualifiedPathType::create_error ();
     579            0 :     }
     580              : 
     581              :   // parse optional as clause
     582          428 :   AST::TypePath as_type_path = AST::TypePath::create_error ();
     583          856 :   if (lexer.peek_token ()->get_id () == AS)
     584              :     {
     585          393 :       lexer.skip_token ();
     586              : 
     587              :       // parse type path, which is required now
     588          393 :       as_type_path = parse_type_path ();
     589          393 :       if (as_type_path.is_error ())
     590              :         {
     591            0 :           Error error (
     592            0 :             lexer.peek_token ()->get_locus (),
     593              :             "could not parse type path in as clause in qualified path type");
     594            0 :           add_error (std::move (error));
     595              : 
     596              :           // skip somewhere?
     597            0 :           return AST::QualifiedPathType::create_error ();
     598            0 :         }
     599              :     }
     600              : 
     601              :   /* NOTE: should actually be a right-angle token, so
     602              :    * skip_generics_right_angle shouldn't be required */
     603          428 :   if (!skip_token (RIGHT_ANGLE))
     604              :     {
     605              :       // skip after somewhere?
     606            0 :       return AST::QualifiedPathType::create_error ();
     607              :     }
     608              : 
     609          428 :   return AST::QualifiedPathType (std::move (type), locus,
     610          428 :                                  std::move (as_type_path));
     611          428 : }
     612              : 
     613              : // Parses a fully qualified path in type (i.e. a type).
     614              : template <typename ManagedTokenSource>
     615              : AST::QualifiedPathInType
     616          331 : Parser<ManagedTokenSource>::parse_qualified_path_in_type ()
     617              : {
     618          331 :   location_t locus = lexer.peek_token ()->get_locus ();
     619              :   // parse the qualified path type (required)
     620          331 :   AST::QualifiedPathType qual_path_type = parse_qualified_path_type ();
     621          331 :   if (qual_path_type.is_error ())
     622              :     {
     623              :       // TODO: should this create a parse error?
     624            0 :       return AST::QualifiedPathInType::create_error ();
     625              :     }
     626              : 
     627              :   // parse initial required segment
     628          662 :   if (!expect_token (SCOPE_RESOLUTION))
     629              :     {
     630              :       // skip after somewhere?
     631              : 
     632            0 :       return AST::QualifiedPathInType::create_error ();
     633              :     }
     634          331 :   std::unique_ptr<AST::TypePathSegment> initial_segment
     635              :     = parse_type_path_segment ();
     636          331 :   if (initial_segment == nullptr)
     637              :     {
     638              :       // skip after somewhere?
     639            0 :       Error error (lexer.peek_token ()->get_locus (),
     640              :                    "required initial type path segment in qualified path in "
     641              :                    "type could not be parsed");
     642            0 :       add_error (std::move (error));
     643              : 
     644            0 :       return AST::QualifiedPathInType::create_error ();
     645            0 :     }
     646              : 
     647              :   // parse optional segments (as long as scope resolution operator exists)
     648          331 :   std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
     649          331 :   const_TokenPtr t = lexer.peek_token ();
     650          331 :   while (t->get_id () == SCOPE_RESOLUTION)
     651              :     {
     652              :       // skip scope resolution operator
     653            0 :       lexer.skip_token ();
     654              : 
     655              :       // parse the actual segment - it is an error if it doesn't exist now
     656            0 :       std::unique_ptr<AST::TypePathSegment> segment
     657              :         = parse_type_path_segment ();
     658            0 :       if (segment == nullptr)
     659              :         {
     660              :           // skip after somewhere?
     661            0 :           Error error (
     662              :             t->get_locus (),
     663              :             "could not parse type path segment in qualified path in type");
     664            0 :           add_error (std::move (error));
     665              : 
     666            0 :           return AST::QualifiedPathInType::create_error ();
     667            0 :         }
     668              : 
     669            0 :       segments.push_back (std::move (segment));
     670              : 
     671            0 :       t = lexer.peek_token ();
     672              :     }
     673              : 
     674          331 :   segments.shrink_to_fit ();
     675              : 
     676          662 :   return AST::QualifiedPathInType (std::move (qual_path_type),
     677              :                                    std::move (initial_segment),
     678          331 :                                    std::move (segments), locus);
     679          331 : }
     680              : } // 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.