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 106901 : Parser<ManagedTokenSource>::parse_simple_path ()
31 : {
32 106901 : bool has_opening_scope_resolution = false;
33 106901 : 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 213802 : if (!is_simple_path_segment (lexer.peek_token ()->get_id ())
39 138971 : && !is_simple_path_segment (lexer.peek_token (1)->get_id ()))
40 28980 : 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 155842 : 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 77921 : auto segment = parse_simple_path_segment ();
55 :
56 77921 : if (!segment)
57 3090 : return tl::unexpected<Parse::Error::Node> (Parse::Error::Node::CHILD_ERROR);
58 :
59 : // get location if not gotten already
60 74831 : if (locus == UNKNOWN_LOCATION)
61 74831 : locus = segment->get_locus ();
62 :
63 74831 : std::vector<AST::SimplePathSegment> segments;
64 74831 : segments.push_back (std::move (segment.value ()));
65 :
66 : // Parse all other simple path segments
67 157959 : while (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
68 : {
69 4562 : 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 4562 : if (!new_segment)
74 : {
75 827 : 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 3735 : segments.push_back (std::move (new_segment.value ()));
83 : }
84 :
85 74831 : return AST::SimplePath (std::move (segments), has_opening_scope_resolution,
86 74831 : 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 74831 : }
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 82483 : Parser<ManagedTokenSource>::parse_simple_path_segment (int base_peek)
97 : {
98 : using namespace Values;
99 82483 : const_TokenPtr t = lexer.peek_token (base_peek);
100 82483 : switch (t->get_id ())
101 : {
102 77032 : case IDENTIFIER:
103 77032 : lexer.skip_token (base_peek);
104 :
105 154064 : return AST::SimplePathSegment (t->get_str (), t->get_locus ());
106 468 : case SUPER:
107 468 : lexer.skip_token (base_peek);
108 :
109 468 : return AST::SimplePathSegment (Keywords::SUPER, t->get_locus ());
110 315 : case SELF:
111 315 : lexer.skip_token (base_peek);
112 :
113 315 : return AST::SimplePathSegment (Keywords::SELF, t->get_locus ());
114 751 : case CRATE:
115 751 : lexer.skip_token (base_peek);
116 :
117 751 : 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 3917 : return Parse::Error::SimplePathSegment::make_invalid_token_or_path_end ();
132 : }
133 : rust_unreachable ();
134 82483 : }
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 590377 : Parser<ManagedTokenSource>::parse_path_ident_segment ()
140 : {
141 590377 : const_TokenPtr t = lexer.peek_token ();
142 590377 : switch (t->get_id ())
143 : {
144 550194 : case IDENTIFIER:
145 550194 : lexer.skip_token ();
146 :
147 1100388 : return AST::PathIdentSegment (t->get_str (), t->get_locus ());
148 86 : case SUPER:
149 86 : lexer.skip_token ();
150 :
151 86 : return AST::PathIdentSegment (Values::Keywords::SUPER, t->get_locus ());
152 23272 : case SELF:
153 23272 : lexer.skip_token ();
154 :
155 23272 : return AST::PathIdentSegment (Values::Keywords::SELF, t->get_locus ());
156 15225 : case SELF_ALIAS:
157 15225 : lexer.skip_token ();
158 :
159 30450 : return AST::PathIdentSegment (Values::Keywords::SELF_ALIAS,
160 15225 : t->get_locus ());
161 1349 : case CRATE:
162 1349 : lexer.skip_token ();
163 :
164 1349 : 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 251 : return Parse::Error::PathIdentSegment::make_invalid_token ();
180 : }
181 : rust_unreachable ();
182 590377 : }
183 :
184 : // Parses a type path.
185 : template <typename ManagedTokenSource>
186 : AST::TypePath
187 140771 : Parser<ManagedTokenSource>::parse_type_path ()
188 : {
189 140771 : bool has_opening_scope_resolution = false;
190 140771 : location_t locus = lexer.peek_token ()->get_locus ();
191 281542 : 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 140771 : std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
199 :
200 : // parse required initial segment
201 140771 : std::unique_ptr<AST::TypePathSegment> initial_segment
202 : = parse_type_path_segment ();
203 140771 : if (initial_segment == nullptr)
204 : {
205 : // skip after somewhere?
206 : // don't necessarily throw error but yeah
207 240 : return AST::TypePath::create_error ();
208 : }
209 140531 : segments.push_back (std::move (initial_segment));
210 :
211 : // parse optional segments (as long as scope resolution operator exists)
212 140531 : const_TokenPtr t = lexer.peek_token ();
213 145492 : while (t->get_id () == SCOPE_RESOLUTION)
214 : {
215 : // skip scope resolution operator
216 4961 : lexer.skip_token ();
217 :
218 : // parse the actual segment - it is an error if it doesn't exist now
219 4961 : std::unique_ptr<AST::TypePathSegment> segment
220 : = parse_type_path_segment ();
221 4961 : 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 4961 : segments.push_back (std::move (segment));
231 :
232 4961 : t = lexer.peek_token ();
233 : }
234 :
235 140531 : segments.shrink_to_fit ();
236 :
237 281062 : return AST::TypePath (std::move (segments), locus,
238 140531 : has_opening_scope_resolution);
239 140771 : }
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 149313 : Parser<ManagedTokenSource>::parse_type_path_segment ()
247 : {
248 149313 : location_t locus = lexer.peek_token ()->get_locus ();
249 : // parse ident segment part
250 149313 : auto ident_segment_res = parse_path_ident_segment ();
251 149313 : if (!ident_segment_res)
252 : {
253 : // not necessarily an error
254 240 : return nullptr;
255 : }
256 149073 : auto ident_segment = ident_segment_res.value ();
257 :
258 : /* lookahead to determine if variants exist - only consume scope resolution
259 : * then */
260 149073 : bool has_separating_scope_resolution = false;
261 149073 : const_TokenPtr next = lexer.peek_token (1);
262 298146 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
263 149073 : && (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 149073 : const_TokenPtr t = lexer.peek_token ();
271 149073 : switch (t->get_id ())
272 : {
273 20931 : case LEFT_SHIFT:
274 : case LEFT_ANGLE:
275 : {
276 : // parse generic args
277 20931 : AST::GenericArgs generic_args = parse_path_generic_args ();
278 :
279 20931 : return std::unique_ptr<AST::TypePathSegmentGeneric> (
280 41862 : new AST::TypePathSegmentGeneric (std::move (ident_segment),
281 : has_separating_scope_resolution,
282 20931 : std::move (generic_args), locus));
283 20931 : }
284 613 : case LEFT_PAREN:
285 : {
286 : // parse type path function
287 613 : AST::TypePathFunction type_path_function
288 : = parse_type_path_function (locus);
289 :
290 613 : if (type_path_function.is_error ())
291 : {
292 : // skip after somewhere?
293 0 : return nullptr;
294 : }
295 :
296 613 : return std::unique_ptr<AST::TypePathSegmentFunction> (
297 1839 : new AST::TypePathSegmentFunction (std::move (ident_segment),
298 : has_separating_scope_resolution,
299 : std::move (type_path_function),
300 613 : locus));
301 613 : }
302 127529 : default:
303 : // neither of them
304 : return std::unique_ptr<AST::TypePathSegment> (
305 127529 : new AST::TypePathSegment (std::move (ident_segment),
306 127529 : has_separating_scope_resolution, locus));
307 : }
308 : rust_unreachable ();
309 298146 : }
310 :
311 : // Parses a function call representation inside a type path.
312 : template <typename ManagedTokenSource>
313 : AST::TypePathFunction
314 613 : Parser<ManagedTokenSource>::parse_type_path_function (location_t id_location)
315 : {
316 613 : if (!skip_token (LEFT_PAREN))
317 : {
318 : // skip somewhere?
319 0 : return AST::TypePathFunction::create_error ();
320 : }
321 :
322 : // parse function inputs
323 613 : std::vector<std::unique_ptr<AST::Type>> inputs;
324 :
325 2308 : while (lexer.peek_token ()->get_id () != RIGHT_PAREN)
326 : {
327 827 : std::unique_ptr<AST::Type> type = parse_type ();
328 827 : 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 827 : inputs.push_back (std::move (type));
342 :
343 : // skip commas, including trailing commas
344 1654 : if (lexer.peek_token ()->get_id () != COMMA)
345 : break;
346 :
347 248 : lexer.skip_token ();
348 : }
349 :
350 613 : if (!skip_token (RIGHT_PAREN))
351 : {
352 : // skip somewhere?
353 0 : return AST::TypePathFunction::create_error ();
354 : }
355 :
356 : // parse optional return type
357 613 : std::unique_ptr<AST::Type> return_type = parse_function_return_type ();
358 :
359 613 : inputs.shrink_to_fit ();
360 613 : return AST::TypePathFunction (std::move (inputs), id_location,
361 613 : std::move (return_type));
362 613 : }
363 :
364 : // Parses a path inside an expression that allows generic arguments.
365 : template <typename ManagedTokenSource>
366 : AST::PathInExpression
367 388537 : Parser<ManagedTokenSource>::parse_path_in_expression ()
368 : {
369 388537 : location_t locus = UNKNOWN_LOCATION;
370 388537 : bool has_opening_scope_resolution = false;
371 777074 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION)
372 : {
373 12 : has_opening_scope_resolution = true;
374 :
375 12 : locus = lexer.peek_token ()->get_locus ();
376 :
377 12 : lexer.skip_token ();
378 : }
379 :
380 : // create segment vector
381 388537 : std::vector<AST::PathExprSegment> segments;
382 :
383 388537 : if (locus == UNKNOWN_LOCATION)
384 : {
385 777050 : locus = lexer.peek_token ()->get_locus ();
386 : }
387 :
388 : // parse required initial segment
389 388537 : AST::PathExprSegment initial_segment = parse_path_expr_segment ();
390 388537 : if (initial_segment.is_error ())
391 : {
392 7 : if (has_opening_scope_resolution)
393 : {
394 3 : Error error (locus, "expected identifier");
395 3 : add_error (std::move (error));
396 3 : }
397 7 : return AST::PathInExpression::create_error ();
398 : }
399 388530 : segments.push_back (std::move (initial_segment));
400 :
401 : // parse optional segments (as long as scope resolution operator exists)
402 388530 : const_TokenPtr t = lexer.peek_token ();
403 407699 : while (t->get_id () == SCOPE_RESOLUTION)
404 : {
405 : // skip scope resolution operator
406 19169 : lexer.skip_token ();
407 :
408 : // parse the actual segment - it is an error if it doesn't exist now
409 19169 : AST::PathExprSegment segment = parse_path_expr_segment ();
410 19169 : if (segment.is_error ())
411 : {
412 : // skip after somewhere?
413 4 : Error error (t->get_locus (),
414 : "could not parse path expression segment");
415 4 : add_error (std::move (error));
416 :
417 4 : return AST::PathInExpression::create_error ();
418 4 : }
419 :
420 19165 : segments.push_back (std::move (segment));
421 :
422 19165 : t = lexer.peek_token ();
423 : }
424 :
425 388526 : segments.shrink_to_fit ();
426 :
427 388526 : return AST::PathInExpression (std::move (segments), {}, locus,
428 388526 : has_opening_scope_resolution);
429 777067 : }
430 :
431 : /* Parses a single path in expression path segment (including generic
432 : * arguments). */
433 : template <typename ManagedTokenSource>
434 : AST::PathExprSegment
435 441064 : Parser<ManagedTokenSource>::parse_path_expr_segment ()
436 : {
437 441064 : location_t locus = lexer.peek_token ()->get_locus ();
438 : // parse ident segment
439 441064 : auto ident_result = parse_path_ident_segment ();
440 441064 : if (!ident_result)
441 : {
442 : // not necessarily an error?
443 11 : return AST::PathExprSegment::create_error ();
444 : }
445 441053 : auto ident = ident_result.value ();
446 :
447 : // parse generic args (and turbofish), if they exist
448 : /* use lookahead to determine if they actually exist (don't want to
449 : * accidently parse over next ident segment) */
450 882106 : if (lexer.peek_token ()->get_id () == SCOPE_RESOLUTION
451 882106 : && (lexer.peek_token (1)->get_id () == LEFT_ANGLE
452 460084 : || lexer.peek_token (1)->get_id () == LEFT_SHIFT))
453 : {
454 : // skip scope resolution
455 1612 : lexer.skip_token ();
456 :
457 : // Let parse_path_generic_args split "<<" tokens
458 1612 : AST::GenericArgs generic_args = parse_path_generic_args ();
459 :
460 3224 : return AST::PathExprSegment (std::move (ident), locus,
461 1612 : std::move (generic_args));
462 1612 : }
463 :
464 : // return a generic parameter-less expr segment if not found
465 439441 : return AST::PathExprSegment (std::move (ident), locus);
466 441053 : }
467 :
468 : /* Parses a fully qualified path in expression (i.e. a pattern). FIXME does
469 : * not parse outer attrs. */
470 : template <typename ManagedTokenSource>
471 : AST::QualifiedPathInExpression
472 213 : Parser<ManagedTokenSource>::parse_qualified_path_in_expression (
473 : location_t pratt_parsed_loc)
474 : {
475 : /* Note: the Rust grammar is defined in such a way that it is impossible to
476 : * determine whether a prospective qualified path is a
477 : * QualifiedPathInExpression or QualifiedPathInType in all cases by the
478 : * rules themselves (the only possible difference is a TypePathSegment with
479 : * function, and lookahead to find this is too difficult). However, as this
480 : * is a pattern and QualifiedPathInType is a type, I believe it that their
481 : * construction will not be confused (due to rules regarding patterns vs
482 : * types).
483 : * As such, this function will not attempt to minimise errors created by
484 : * their confusion. */
485 :
486 : // parse the qualified path type (required)
487 213 : AST::QualifiedPathType qual_path_type
488 : = parse_qualified_path_type (pratt_parsed_loc);
489 213 : if (qual_path_type.is_error ())
490 : {
491 : // TODO: should this create a parse error?
492 0 : return AST::QualifiedPathInExpression::create_error ();
493 : }
494 213 : location_t locus = qual_path_type.get_locus ();
495 :
496 : // parse path segments
497 213 : std::vector<AST::PathExprSegment> segments;
498 :
499 : // parse initial required segment
500 426 : if (!expect_token (SCOPE_RESOLUTION))
501 : {
502 : // skip after somewhere?
503 :
504 0 : return AST::QualifiedPathInExpression::create_error ();
505 : }
506 213 : AST::PathExprSegment initial_segment = parse_path_expr_segment ();
507 213 : if (initial_segment.is_error ())
508 : {
509 : // skip after somewhere?
510 0 : Error error (lexer.peek_token ()->get_locus (),
511 : "required initial path expression segment in "
512 : "qualified path in expression could not be parsed");
513 0 : add_error (std::move (error));
514 :
515 0 : return AST::QualifiedPathInExpression::create_error ();
516 0 : }
517 213 : segments.push_back (std::move (initial_segment));
518 :
519 : // parse optional segments (as long as scope resolution operator exists)
520 213 : const_TokenPtr t = lexer.peek_token ();
521 214 : while (t->get_id () == SCOPE_RESOLUTION)
522 : {
523 : // skip scope resolution operator
524 1 : lexer.skip_token ();
525 :
526 : // parse the actual segment - it is an error if it doesn't exist now
527 1 : AST::PathExprSegment segment = parse_path_expr_segment ();
528 1 : if (segment.is_error ())
529 : {
530 : // skip after somewhere?
531 0 : Error error (t->get_locus (),
532 : "could not parse path expression segment in qualified "
533 : "path in expression");
534 0 : add_error (std::move (error));
535 :
536 0 : return AST::QualifiedPathInExpression::create_error ();
537 0 : }
538 :
539 1 : segments.push_back (std::move (segment));
540 :
541 1 : t = lexer.peek_token ();
542 : }
543 :
544 213 : segments.shrink_to_fit ();
545 :
546 : // FIXME: outer attr parsing
547 426 : return AST::QualifiedPathInExpression (std::move (qual_path_type),
548 213 : std::move (segments), {}, locus);
549 426 : }
550 :
551 : // Parses the type syntactical construction at the start of a qualified path.
552 : template <typename ManagedTokenSource>
553 : AST::QualifiedPathType
554 3794 : Parser<ManagedTokenSource>::parse_qualified_path_type (
555 : location_t pratt_parsed_loc)
556 : {
557 3794 : location_t locus = pratt_parsed_loc;
558 : /* TODO: should this actually be error? is there anywhere where this could
559 : * be valid? */
560 3794 : if (locus == UNKNOWN_LOCATION)
561 : {
562 3581 : locus = lexer.peek_token ()->get_locus ();
563 :
564 7162 : if (lexer.peek_token ()->get_id () == LEFT_SHIFT)
565 2 : lexer.split_current_token (LEFT_ANGLE, LEFT_ANGLE);
566 :
567 : // skip after somewhere?
568 3581 : if (!skip_token (LEFT_ANGLE))
569 0 : return AST::QualifiedPathType::create_error ();
570 : }
571 :
572 : // parse type (required)
573 3794 : std::unique_ptr<AST::Type> type = parse_type ();
574 3794 : if (type == nullptr)
575 : {
576 0 : Error error (lexer.peek_token ()->get_locus (),
577 : "could not parse type in qualified path type");
578 0 : add_error (std::move (error));
579 :
580 : // skip somewhere?
581 0 : return AST::QualifiedPathType::create_error ();
582 0 : }
583 :
584 : // parse optional as clause
585 3794 : AST::TypePath as_type_path = AST::TypePath::create_error ();
586 7588 : if (lexer.peek_token ()->get_id () == AS)
587 : {
588 3673 : lexer.skip_token ();
589 :
590 : // parse type path, which is required now
591 3673 : as_type_path = parse_type_path ();
592 3673 : if (as_type_path.is_error ())
593 : {
594 0 : Error error (
595 0 : lexer.peek_token ()->get_locus (),
596 : "could not parse type path in as clause in qualified path type");
597 0 : add_error (std::move (error));
598 :
599 : // skip somewhere?
600 0 : return AST::QualifiedPathType::create_error ();
601 0 : }
602 : }
603 :
604 : /* NOTE: should actually be a right-angle token, so
605 : * skip_generics_right_angle shouldn't be required */
606 3794 : if (!skip_token (RIGHT_ANGLE))
607 : {
608 : // skip after somewhere?
609 0 : return AST::QualifiedPathType::create_error ();
610 : }
611 :
612 3794 : return AST::QualifiedPathType (std::move (type), locus,
613 3794 : std::move (as_type_path));
614 3794 : }
615 :
616 : // Parses a fully qualified path in type (i.e. a type).
617 : template <typename ManagedTokenSource>
618 : AST::QualifiedPathInType
619 3581 : Parser<ManagedTokenSource>::parse_qualified_path_in_type ()
620 : {
621 3581 : location_t locus = lexer.peek_token ()->get_locus ();
622 : // parse the qualified path type (required)
623 3581 : AST::QualifiedPathType qual_path_type = parse_qualified_path_type ();
624 3581 : if (qual_path_type.is_error ())
625 : {
626 : // TODO: should this create a parse error?
627 0 : return AST::QualifiedPathInType::create_error ();
628 : }
629 :
630 : // parse initial required segment
631 7162 : if (!expect_token (SCOPE_RESOLUTION))
632 : {
633 : // skip after somewhere?
634 :
635 0 : return AST::QualifiedPathInType::create_error ();
636 : }
637 3581 : std::unique_ptr<AST::TypePathSegment> initial_segment
638 : = parse_type_path_segment ();
639 3581 : if (initial_segment == nullptr)
640 : {
641 : // skip after somewhere?
642 0 : Error error (lexer.peek_token ()->get_locus (),
643 : "required initial type path segment in qualified path in "
644 : "type could not be parsed");
645 0 : add_error (std::move (error));
646 :
647 0 : return AST::QualifiedPathInType::create_error ();
648 0 : }
649 :
650 : // parse optional segments (as long as scope resolution operator exists)
651 3581 : std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
652 3581 : const_TokenPtr t = lexer.peek_token ();
653 3581 : while (t->get_id () == SCOPE_RESOLUTION)
654 : {
655 : // skip scope resolution operator
656 0 : lexer.skip_token ();
657 :
658 : // parse the actual segment - it is an error if it doesn't exist now
659 0 : std::unique_ptr<AST::TypePathSegment> segment
660 : = parse_type_path_segment ();
661 0 : if (segment == nullptr)
662 : {
663 : // skip after somewhere?
664 0 : Error error (
665 : t->get_locus (),
666 : "could not parse type path segment in qualified path in type");
667 0 : add_error (std::move (error));
668 :
669 0 : return AST::QualifiedPathInType::create_error ();
670 0 : }
671 :
672 0 : segments.push_back (std::move (segment));
673 :
674 0 : t = lexer.peek_token ();
675 : }
676 :
677 3581 : segments.shrink_to_fit ();
678 :
679 7162 : return AST::QualifiedPathInType (std::move (qual_path_type),
680 : std::move (initial_segment),
681 3581 : std::move (segments), locus);
682 3581 : }
683 : } // namespace Rust
|