// Copyright (C) 2025-2026 Free Software Foundation, Inc. // This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . /* DO NOT INCLUDE ANYWHERE - this is automatically included * by rust-parse-impl.h * This is also the reason why there are no include guards. */ #include "rust-parse.h" namespace Rust { template std::unique_ptr Parser::parse_pattern () { location_t start_locus = lexer.peek_token ()->get_locus (); /* skip optional starting pipe */ maybe_skip_token (PIPE); auto first = parse_pattern_no_alt (); if (lexer.peek_token ()->get_id () != PIPE) /* no alternates */ return first; std::vector> alts; if (first != nullptr) alts.push_back (std::move (first)); do { lexer.skip_token (); auto follow = parse_pattern_no_alt (); if (follow != nullptr) alts.push_back (std::move (follow)); } while (lexer.peek_token ()->get_id () == PIPE); if (alts.empty ()) return nullptr; /* alternates */ return std::unique_ptr ( new AST::AltPattern (std::move (alts), start_locus)); } // Parses a pattern without alternates ('|') // (will further disambiguate any pattern). template std::unique_ptr Parser::parse_pattern_no_alt () { const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { case TRUE_LITERAL: lexer.skip_token (); return std::unique_ptr ( new AST::LiteralPattern (Values::Keywords::TRUE_LITERAL, AST::Literal::BOOL, t->get_locus (), t->get_type_hint ())); case FALSE_LITERAL: lexer.skip_token (); return std::unique_ptr ( new AST::LiteralPattern (Values::Keywords::FALSE_LITERAL, AST::Literal::BOOL, t->get_locus (), t->get_type_hint ())); case CHAR_LITERAL: case BYTE_CHAR_LITERAL: case INT_LITERAL: case FLOAT_LITERAL: return parse_literal_or_range_pattern (); case STRING_LITERAL: lexer.skip_token (); return std::unique_ptr ( new AST::LiteralPattern (t->get_str (), AST::Literal::STRING, t->get_locus (), t->get_type_hint ())); case BYTE_STRING_LITERAL: lexer.skip_token (); return std::unique_ptr ( new AST::LiteralPattern (t->get_str (), AST::Literal::BYTE_STRING, t->get_locus (), t->get_type_hint ())); case RAW_STRING_LITERAL: lexer.skip_token (); return std::unique_ptr ( new AST::LiteralPattern (t->get_str (), AST::Literal::RAW_STRING, t->get_locus (), t->get_type_hint ())); // raw string and raw byte string literals too if they are readded to // lexer case MINUS: if (lexer.peek_token (1)->get_id () == INT_LITERAL) { return parse_literal_or_range_pattern (); } else if (lexer.peek_token (1)->get_id () == FLOAT_LITERAL) { return parse_literal_or_range_pattern (); } else { Error error (t->get_locus (), "unexpected token %<-%> in pattern - " "did you forget an integer literal"); add_error (std::move (error)); return nullptr; } case UNDERSCORE: lexer.skip_token (); return std::unique_ptr ( new AST::WildcardPattern (t->get_locus ())); case DOT_DOT: lexer.skip_token (); return std::unique_ptr ( new AST::RestPattern (t->get_locus ())); case REF: case MUT: return parse_identifier_pattern (); case IDENTIFIER: /* if identifier with no scope resolution afterwards, identifier * pattern. if scope resolution afterwards, path pattern (or range * pattern or struct pattern or tuple struct pattern) or macro * invocation */ return parse_ident_leading_pattern (); case AMP: case LOGICAL_AND: // reference pattern return parse_reference_pattern (); case LEFT_PAREN: // tuple pattern or grouped pattern return parse_grouped_or_tuple_pattern (); case LEFT_SQUARE: // slice pattern return parse_slice_pattern (); case LEFT_SHIFT: case LEFT_ANGLE: { // qualified path in expression or qualified range pattern bound AST::QualifiedPathInExpression path = parse_qualified_path_in_expression (); if (lexer.peek_token ()->get_id () == DOT_DOT_EQ || lexer.peek_token ()->get_id () == ELLIPSIS || lexer.peek_token ()->get_id () == DOT_DOT) { // qualified range pattern bound, so parse rest of range pattern AST::RangeKind kind = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ()); lexer.skip_token (); std::unique_ptr lower_bound ( new AST::RangePatternBoundQualPath (std::move (path))); std::unique_ptr upper_bound = parse_range_pattern_bound (); return std::unique_ptr ( new AST::RangePattern (std::move (lower_bound), std::move (upper_bound), kind, t->get_locus ())); } else { // just qualified path in expression return std::unique_ptr ( new AST::QualifiedPathInExpression (std::move (path))); } } case SUPER: case SELF: case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: case DOLLAR_SIGN: { // path in expression or range pattern bound AST::PathInExpression path = parse_path_in_expression (); const_TokenPtr next = lexer.peek_token (); switch (next->get_id ()) { case DOT_DOT_EQ: case DOT_DOT: case ELLIPSIS: { // qualified range pattern bound, so parse rest of range pattern AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ()); lexer.skip_token (); std::unique_ptr lower_bound ( new AST::RangePatternBoundPath (std::move (path))); std::unique_ptr upper_bound = parse_range_pattern_bound (); return std::unique_ptr ( new AST::RangePattern (std::move (lower_bound), std::move (upper_bound), kind, next->get_locus ())); } case EXCLAM: return parse_macro_invocation_partial (std::move (path), AST::AttrVec ()); case LEFT_PAREN: { // tuple struct lexer.skip_token (); // parse items std::unique_ptr items = parse_tuple_struct_items (); if (items == nullptr) { Error error (lexer.peek_token ()->get_locus (), "failed to parse tuple struct items"); add_error (std::move (error)); return nullptr; } if (!skip_token (RIGHT_PAREN)) { return nullptr; } return std::unique_ptr ( new AST::TupleStructPattern (std::move (path), std::move (items))); } case LEFT_CURLY: { // struct lexer.skip_token (); // parse elements (optional) AST::StructPatternElements elems = parse_struct_pattern_elems (); if (!skip_token (RIGHT_CURLY)) { return nullptr; } return std::unique_ptr ( new AST::StructPattern (std::move (path), t->get_locus (), std::move (elems))); } default: // assume path in expression return std::unique_ptr ( new AST::PathInExpression (std::move (path))); } } default: add_error (Error (t->get_locus (), "unexpected token %qs in pattern", t->get_token_description ())); return nullptr; } } // Parses a single or double reference pattern. template std::unique_ptr Parser::parse_reference_pattern () { // parse double or single ref bool is_double_ref = false; const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { case AMP: // still false lexer.skip_token (); break; case LOGICAL_AND: is_double_ref = true; lexer.skip_token (); break; default: add_error (Error (t->get_locus (), "unexpected token %qs in reference pattern", t->get_token_description ())); return nullptr; } // parse mut (if it exists) bool is_mut = false; if (lexer.peek_token ()->get_id () == MUT) { is_mut = true; lexer.skip_token (); } // parse pattern to get reference of (required) std::unique_ptr pattern = parse_pattern_no_alt (); if (pattern == nullptr) { Error error (lexer.peek_token ()->get_locus (), "failed to parse pattern in reference pattern"); add_error (std::move (error)); // skip somewhere? return nullptr; } return std::unique_ptr ( new AST::ReferencePattern (std::move (pattern), is_mut, is_double_ref, t->get_locus ())); } /* Parses a grouped pattern or tuple pattern. Prefers grouped over tuple if * only a single element with no commas. */ template std::unique_ptr Parser::parse_grouped_or_tuple_pattern () { location_t paren_locus = lexer.peek_token ()->get_locus (); skip_token (LEFT_PAREN); // detect '..' token (ranged with no lower range) if (lexer.peek_token ()->get_id () == DOT_DOT) { lexer.skip_token (); // parse new patterns while next token is a comma std::vector> patterns; const_TokenPtr t = lexer.peek_token (); while (t->get_id () == COMMA) { lexer.skip_token (); // break if next token is ')' if (lexer.peek_token ()->get_id () == RIGHT_PAREN) { break; } // parse pattern, which is required std::unique_ptr pattern = parse_pattern (); if (pattern == nullptr) { Error error ( lexer.peek_token ()->get_locus (), "failed to parse pattern inside ranged tuple pattern"); add_error (std::move (error)); // skip somewhere? return nullptr; } patterns.push_back (std::move (pattern)); t = lexer.peek_token (); } if (!skip_token (RIGHT_PAREN)) { // skip somewhere? return nullptr; } // create tuple pattern items with only upper pattern items std::unique_ptr items ( new AST::TuplePatternItemsHasRest ( std::vector> (), std::move (patterns))); return std::unique_ptr ( new AST::TuplePattern (std::move (items), paren_locus)); } else if (lexer.peek_token ()->get_id () == RIGHT_PAREN) { skip_token (RIGHT_PAREN); auto items = std::unique_ptr ( new AST::TuplePatternItemsNoRest ( std::vector> ())); return std::unique_ptr ( new AST::TuplePattern (std::move (items), paren_locus)); } // parse initial pattern (required) std::unique_ptr initial_pattern = parse_pattern (); if (initial_pattern == nullptr) { Error error (lexer.peek_token ()->get_locus (), "failed to parse pattern in grouped or tuple pattern"); add_error (std::move (error)); return nullptr; } // branch on whether next token is a comma or not const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { case RIGHT_PAREN: // grouped pattern lexer.skip_token (); return std::unique_ptr ( new AST::GroupedPattern (std::move (initial_pattern), paren_locus)); case COMMA: { // tuple pattern lexer.skip_token (); // create vector of patterns std::vector> patterns; patterns.push_back (std::move (initial_pattern)); t = lexer.peek_token (); while (t->get_id () != RIGHT_PAREN && t->get_id () != DOT_DOT) { // parse pattern (required) std::unique_ptr pattern = parse_pattern (); if (pattern == nullptr) { Error error (t->get_locus (), "failed to parse pattern in tuple pattern"); add_error (std::move (error)); return nullptr; } patterns.push_back (std::move (pattern)); if (lexer.peek_token ()->get_id () != COMMA) break; lexer.skip_token (); t = lexer.peek_token (); } t = lexer.peek_token (); if (t->get_id () == RIGHT_PAREN) { // non-ranged tuple pattern lexer.skip_token (); std::unique_ptr items ( new AST::TuplePatternItemsNoRest (std::move (patterns))); return std::unique_ptr ( new AST::TuplePattern (std::move (items), paren_locus)); } else if (t->get_id () == DOT_DOT) { // ranged tuple pattern lexer.skip_token (); // parse upper patterns std::vector> upper_patterns; t = lexer.peek_token (); while (t->get_id () == COMMA) { lexer.skip_token (); // break if end if (lexer.peek_token ()->get_id () == RIGHT_PAREN) break; // parse pattern (required) std::unique_ptr pattern = parse_pattern (); if (pattern == nullptr) { Error error (lexer.peek_token ()->get_locus (), "failed to parse pattern in tuple pattern"); add_error (std::move (error)); return nullptr; } upper_patterns.push_back (std::move (pattern)); t = lexer.peek_token (); } if (!skip_token (RIGHT_PAREN)) { return nullptr; } std::unique_ptr items ( new AST::TuplePatternItemsHasRest (std::move (patterns), std::move (upper_patterns))); return std::unique_ptr ( new AST::TuplePattern (std::move (items), paren_locus)); } else { // some kind of error Error error (t->get_locus (), "failed to parse tuple pattern (probably) or maybe " "grouped pattern"); add_error (std::move (error)); return nullptr; } } default: // error add_error (Error (t->get_locus (), "unrecognised token %qs in grouped or tuple pattern " "after first pattern", t->get_token_description ())); return nullptr; } } /* Parses a slice pattern that can match arrays or slices. Parses the square * brackets too. */ template std::unique_ptr Parser::parse_slice_pattern () { location_t square_locus = lexer.peek_token ()->get_locus (); std::vector> patterns; tl::optional>> upper_patterns = tl::nullopt; // lambda function to determine which vector to push new patterns into auto get_pattern_ref = [&] () -> std::vector> & { return upper_patterns.has_value () ? upper_patterns.value () : patterns; }; skip_token (LEFT_SQUARE); if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) { skip_token (RIGHT_SQUARE); std::unique_ptr items ( new AST::SlicePatternItemsNoRest (std::move (patterns))); return std::unique_ptr ( new AST::SlicePattern (std::move (items), square_locus)); } // parse initial pattern (required) if (lexer.peek_token ()->get_id () == DOT_DOT) { lexer.skip_token (); upper_patterns = std::vector> (); } else { // Not a rest pattern `..`, parse normally std::unique_ptr initial_pattern = parse_pattern (); if (initial_pattern == nullptr) { Error error (lexer.peek_token ()->get_locus (), "failed to parse initial pattern in slice pattern"); add_error (std::move (error)); return nullptr; } patterns.push_back (std::move (initial_pattern)); } const_TokenPtr t = lexer.peek_token (); while (t->get_id () == COMMA) { lexer.skip_token (); // break if end bracket if (lexer.peek_token ()->get_id () == RIGHT_SQUARE) break; if (lexer.peek_token ()->get_id () == DOT_DOT) { if (upper_patterns.has_value ()) { // DOT_DOT has been parsed before Error error (lexer.peek_token ()->get_locus (), "%s", "`..` can only be used once per slice pattern"); add_error (std::move (error)); return nullptr; } upper_patterns = std::vector> (); lexer.skip_token (); t = lexer.peek_token (); continue; } // parse pattern (required) std::unique_ptr pattern = parse_pattern (); if (pattern == nullptr) { Error error (lexer.peek_token ()->get_locus (), "failed to parse pattern in slice pattern"); add_error (std::move (error)); return nullptr; } get_pattern_ref ().push_back (std::move (pattern)); t = lexer.peek_token (); } if (!skip_token (RIGHT_SQUARE)) { return nullptr; } if (upper_patterns.has_value ()) { // Slice pattern with rest std::unique_ptr items ( new AST::SlicePatternItemsHasRest ( std::move (patterns), std::move (upper_patterns.value ()))); return std::unique_ptr ( new AST::SlicePattern (std::move (items), square_locus)); } // Rest-less slice pattern std::unique_ptr items ( new AST::SlicePatternItemsNoRest (std::move (patterns))); return std::unique_ptr ( new AST::SlicePattern (std::move (items), square_locus)); } /* Parses an identifier pattern (pattern that binds a value matched to a * variable). */ template std::unique_ptr Parser::parse_identifier_pattern () { location_t locus = lexer.peek_token ()->get_locus (); bool has_ref = false; if (lexer.peek_token ()->get_id () == REF) { has_ref = true; lexer.skip_token (); // DEBUG rust_debug ("parsed ref in identifier pattern"); } bool has_mut = false; if (lexer.peek_token ()->get_id () == MUT) { has_mut = true; lexer.skip_token (); } // parse identifier (required) const_TokenPtr ident_tok = expect_token (IDENTIFIER); if (ident_tok == nullptr) { // skip somewhere? return nullptr; } Identifier ident{ident_tok}; // DEBUG rust_debug ("parsed identifier in identifier pattern"); // parse optional pattern binding thing std::unique_ptr bind_pattern = nullptr; if (lexer.peek_token ()->get_id () == PATTERN_BIND) { lexer.skip_token (); // parse required pattern to bind bind_pattern = parse_pattern_no_alt (); if (bind_pattern == nullptr) { Error error (lexer.peek_token ()->get_locus (), "failed to parse pattern to bind in identifier pattern"); add_error (std::move (error)); return nullptr; } } // DEBUG rust_debug ("about to return identifier pattern"); return std::unique_ptr ( new AST::IdentifierPattern (std::move (ident), locus, has_ref, has_mut, std::move (bind_pattern))); } /* Parses a pattern that opens with an identifier. This includes identifier * patterns, path patterns (and derivatives such as struct patterns, tuple * struct patterns, and macro invocations), and ranges. */ template std::unique_ptr Parser::parse_ident_leading_pattern () { // ensure first token is actually identifier const_TokenPtr initial_tok = lexer.peek_token (); if (initial_tok->get_id () != IDENTIFIER) { return nullptr; } // save initial identifier as it may be useful (but don't skip) std::string initial_ident = initial_tok->get_str (); // parse next tokens as a PathInExpression AST::PathInExpression path = parse_path_in_expression (); // branch on next token const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { case EXCLAM: return parse_macro_invocation_partial (std::move (path), AST::AttrVec ()); case LEFT_PAREN: { // tuple struct lexer.skip_token (); // DEBUG rust_debug ("parsing tuple struct pattern"); // parse items std::unique_ptr items = parse_tuple_struct_items (); if (items == nullptr) { Error error (lexer.peek_token ()->get_locus (), "failed to parse tuple struct items"); add_error (std::move (error)); return nullptr; } // DEBUG rust_debug ("successfully parsed tuple struct items"); if (!skip_token (RIGHT_PAREN)) { return nullptr; } // DEBUG rust_debug ("successfully parsed tuple struct pattern"); return std::unique_ptr ( new AST::TupleStructPattern (std::move (path), std::move (items))); } case LEFT_CURLY: { // struct lexer.skip_token (); // parse elements (optional) AST::StructPatternElements elems = parse_struct_pattern_elems (); if (!skip_token (RIGHT_CURLY)) { return nullptr; } // DEBUG rust_debug ("successfully parsed struct pattern"); return std::unique_ptr ( new AST::StructPattern (std::move (path), initial_tok->get_locus (), std::move (elems))); } case DOT_DOT_EQ: case DOT_DOT: case ELLIPSIS: { // range AST::RangeKind kind = AST::tokenid_to_rangekind (lexer.peek_token ()->get_id ()); lexer.skip_token (); std::unique_ptr lower_bound ( new AST::RangePatternBoundPath (std::move (path))); std::unique_ptr upper_bound = parse_range_pattern_bound (); return std::unique_ptr ( new AST::RangePattern (std::move (lower_bound), std::move (upper_bound), kind, t->get_locus ())); } case PATTERN_BIND: { // only allow on single-segment paths if (path.is_single_segment ()) { // identifier with pattern bind lexer.skip_token (); std::unique_ptr bind_pattern = parse_pattern_no_alt (); if (bind_pattern == nullptr) { Error error ( t->get_locus (), "failed to parse pattern to bind to identifier pattern"); add_error (std::move (error)); return nullptr; } return std::unique_ptr ( new AST::IdentifierPattern (std::move (initial_ident), initial_tok->get_locus (), false, false, std::move (bind_pattern))); } Error error ( t->get_locus (), "failed to parse pattern bind to a path, not an identifier"); add_error (std::move (error)); return nullptr; } default: // assume identifier if single segment if (path.is_single_segment ()) { return std::unique_ptr ( new AST::IdentifierPattern (std::move (initial_ident), initial_tok->get_locus ())); } // return path otherwise return std::unique_ptr ( new AST::PathInExpression (std::move (path))); } } // Parses struct pattern elements if they exist. template AST::StructPatternElements Parser::parse_struct_pattern_elems () { std::vector> fields; AST::AttrVec etc_attrs; bool has_rest = false; // try parsing struct pattern fields const_TokenPtr t = lexer.peek_token (); while (t->get_id () != RIGHT_CURLY) { AST::AttrVec outer_attrs = parse_outer_attributes (); // parse etc (must be last in struct pattern, so breaks) if (lexer.peek_token ()->get_id () == DOT_DOT) { lexer.skip_token (); etc_attrs = std::move (outer_attrs); has_rest = true; break; } std::unique_ptr field = parse_struct_pattern_field_partial (std::move (outer_attrs)); if (field == nullptr) { Error error (lexer.peek_token ()->get_locus (), "failed to parse struct pattern field"); add_error (std::move (error)); // skip after somewhere? return AST::StructPatternElements::create_empty (); } fields.push_back (std::move (field)); if (lexer.peek_token ()->get_id () != COMMA) break; // skip comma lexer.skip_token (); t = lexer.peek_token (); } if (has_rest) return AST::StructPatternElements (std::move (fields), std::move (etc_attrs)); else return AST::StructPatternElements (std::move (fields)); } /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or * identifier). */ template std::unique_ptr Parser::parse_struct_pattern_field () { // parse outer attributes (if they exist) AST::AttrVec outer_attrs = parse_outer_attributes (); return parse_struct_pattern_field_partial (std::move (outer_attrs)); } /* Parses a struct pattern field (tuple index/pattern, identifier/pattern, or * identifier), with outer attributes passed in. */ template std::unique_ptr Parser::parse_struct_pattern_field_partial ( AST::AttrVec outer_attrs) { // branch based on next token const_TokenPtr t = lexer.peek_token (); switch (t->get_id ()) { case INT_LITERAL: { // tuple index std::string index_str = t->get_str (); int index = atoi (index_str.c_str ()); lexer.skip_token (); if (!skip_token (COLON)) { return nullptr; } // parse required pattern std::unique_ptr pattern = parse_pattern (); if (pattern == nullptr) { Error error ( t->get_locus (), "failed to parse pattern in tuple index struct pattern field"); add_error (std::move (error)); return nullptr; } return std::unique_ptr ( new AST::StructPatternFieldTuplePat (index, std::move (pattern), std::move (outer_attrs), t->get_locus ())); } case IDENTIFIER: // identifier-pattern OR only identifier // branch on next token switch (lexer.peek_token (1)->get_id ()) { case COLON: { // identifier-pattern Identifier ident{t}; lexer.skip_token (); skip_token (COLON); // parse required pattern std::unique_ptr pattern = parse_pattern (); if (pattern == nullptr) { Error error (t->get_locus (), "failed to parse pattern in struct pattern field"); add_error (std::move (error)); return nullptr; } return std::unique_ptr ( new AST::StructPatternFieldIdentPat (std::move (ident), std::move (pattern), std::move (outer_attrs), t->get_locus ())); } case COMMA: case RIGHT_CURLY: { // identifier only Identifier ident = {t}; lexer.skip_token (); return std::unique_ptr ( new AST::StructPatternFieldIdent (std::move (ident), false, false, std::move (outer_attrs), t->get_locus ())); } default: // error add_error (Error (t->get_locus (), "unrecognised token %qs in struct pattern field", t->get_token_description ())); return nullptr; } case REF: case MUT: { // only identifier bool has_ref = false; if (t->get_id () == REF) { has_ref = true; lexer.skip_token (); } bool has_mut = false; if (lexer.peek_token ()->get_id () == MUT) { has_mut = true; lexer.skip_token (); } const_TokenPtr ident_tok = expect_token (IDENTIFIER); if (ident_tok == nullptr) { return nullptr; } Identifier ident{ident_tok}; return std::unique_ptr ( new AST::StructPatternFieldIdent (std::move (ident), has_ref, has_mut, std::move (outer_attrs), t->get_locus ())); } default: // not necessarily an error return nullptr; } } /* Parses a literal pattern or range pattern. Assumes that literals passed in * are valid range pattern bounds. Do not pass in paths in expressions, for * instance. */ template std::unique_ptr Parser::parse_literal_or_range_pattern () { const_TokenPtr range_lower = lexer.peek_token (); AST::Literal::LitType type = AST::Literal::STRING; bool has_minus = false; // get lit type switch (range_lower->get_id ()) { case CHAR_LITERAL: type = AST::Literal::CHAR; lexer.skip_token (); break; case BYTE_CHAR_LITERAL: type = AST::Literal::BYTE; lexer.skip_token (); break; case INT_LITERAL: type = AST::Literal::INT; lexer.skip_token (); break; case FLOAT_LITERAL: type = AST::Literal::FLOAT; lexer.skip_token (); break; case MINUS: // branch on next token range_lower = lexer.peek_token (1); switch (range_lower->get_id ()) { case INT_LITERAL: type = AST::Literal::INT; has_minus = true; lexer.skip_token (1); break; case FLOAT_LITERAL: type = AST::Literal::FLOAT; has_minus = true; lexer.skip_token (1); break; default: add_error (Error (range_lower->get_locus (), "token type %qs cannot be parsed as range pattern " "bound or literal after minus symbol", range_lower->get_token_description ())); return nullptr; } break; default: add_error ( Error (range_lower->get_locus (), "token type %qs cannot be parsed as range pattern bound", range_lower->get_token_description ())); return nullptr; } const_TokenPtr next = lexer.peek_token (); if (next->get_id () == DOT_DOT_EQ || next->get_id () == ELLIPSIS || next->get_id () == DOT_DOT) { AST::RangeKind kind = AST::tokenid_to_rangekind (next->get_id ()); // range pattern lexer.skip_token (); std::unique_ptr lower ( new AST::RangePatternBoundLiteral ( AST::Literal (range_lower->get_str (), type, PrimitiveCoreType::CORETYPE_UNKNOWN), range_lower->get_locus (), has_minus)); std::unique_ptr upper = parse_range_pattern_bound (); if (upper == nullptr) { Error error (next->get_locus (), "failed to parse range pattern bound in range pattern"); add_error (std::move (error)); return nullptr; } return std::unique_ptr ( new AST::RangePattern (std::move (lower), std::move (upper), kind, range_lower->get_locus ())); } else { // literal pattern return std::unique_ptr ( new AST::LiteralPattern (range_lower->get_str (), type, range_lower->get_locus (), range_lower->get_type_hint (), has_minus)); } } // Parses a range pattern bound (value only). template std::unique_ptr Parser::parse_range_pattern_bound () { const_TokenPtr range_lower = lexer.peek_token (); location_t range_lower_locus = range_lower->get_locus (); // get lit type switch (range_lower->get_id ()) { case CHAR_LITERAL: lexer.skip_token (); return std::unique_ptr ( new AST::RangePatternBoundLiteral ( AST::Literal (range_lower->get_str (), AST::Literal::CHAR, range_lower->get_type_hint ()), range_lower_locus)); case BYTE_CHAR_LITERAL: lexer.skip_token (); return std::unique_ptr ( new AST::RangePatternBoundLiteral ( AST::Literal (range_lower->get_str (), AST::Literal::BYTE, range_lower->get_type_hint ()), range_lower_locus)); case INT_LITERAL: lexer.skip_token (); return std::unique_ptr ( new AST::RangePatternBoundLiteral ( AST::Literal (range_lower->get_str (), AST::Literal::INT, range_lower->get_type_hint ()), range_lower_locus)); case FLOAT_LITERAL: lexer.skip_token (); rust_debug ("warning: used deprecated float range pattern bound"); return std::unique_ptr ( new AST::RangePatternBoundLiteral ( AST::Literal (range_lower->get_str (), AST::Literal::FLOAT, range_lower->get_type_hint ()), range_lower_locus)); case MINUS: // branch on next token range_lower = lexer.peek_token (1); switch (range_lower->get_id ()) { case INT_LITERAL: lexer.skip_token (1); return std::unique_ptr ( new AST::RangePatternBoundLiteral ( AST::Literal (range_lower->get_str (), AST::Literal::INT, range_lower->get_type_hint ()), range_lower_locus, true)); case FLOAT_LITERAL: lexer.skip_token (1); rust_debug ("warning: used deprecated float range pattern bound"); return std::unique_ptr ( new AST::RangePatternBoundLiteral ( AST::Literal (range_lower->get_str (), AST::Literal::FLOAT, range_lower->get_type_hint ()), range_lower_locus, true)); default: add_error (Error (range_lower->get_locus (), "token type %qs cannot be parsed as range pattern " "bound after minus symbol", range_lower->get_token_description ())); return nullptr; } case IDENTIFIER: case SUPER: case SELF: case SELF_ALIAS: case CRATE: case SCOPE_RESOLUTION: case DOLLAR_SIGN: { // path in expression AST::PathInExpression path = parse_path_in_expression (); if (path.is_error ()) { Error error ( range_lower->get_locus (), "failed to parse path in expression range pattern bound"); add_error (std::move (error)); return nullptr; } return std::unique_ptr ( new AST::RangePatternBoundPath (std::move (path))); } case LEFT_SHIFT: case LEFT_ANGLE: { // qualified path in expression AST::QualifiedPathInExpression path = parse_qualified_path_in_expression (); if (path.is_error ()) { Error error (range_lower->get_locus (), "failed to parse qualified path in expression range " "pattern bound"); add_error (std::move (error)); return nullptr; } return std::unique_ptr ( new AST::RangePatternBoundQualPath (std::move (path))); } default: add_error ( Error (range_lower->get_locus (), "token type %qs cannot be parsed as range pattern bound", range_lower->get_token_description ())); return nullptr; } } } // namespace Rust