| // 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 | |
| // <http://www.gnu.org/licenses/>. | |
| /* 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 { | |
| // "Unexpected token" panic mode - flags gcc error at unexpected token | |
| // TODO: seems to be unused, remove? | |
| template <typename ManagedTokenSource> | |
| void | |
| Parser<ManagedTokenSource>::unexpected_token (const_TokenPtr t) | |
| { | |
| Error error (t->get_locus (), "unexpected token %qs", | |
| t->get_token_description ()); | |
| add_error (std::move (error)); | |
| } | |
| /* Crappy "error recovery" performed after error by skipping tokens until a | |
| * semi-colon is found */ | |
| template <typename ManagedTokenSource> | |
| void | |
| Parser<ManagedTokenSource>::skip_after_semicolon () | |
| { | |
| const_TokenPtr t = lexer.peek_token (); | |
| while (t->get_id () != END_OF_FILE && t->get_id () != SEMICOLON) | |
| { | |
| lexer.skip_token (); | |
| t = lexer.peek_token (); | |
| } | |
| if (t->get_id () == SEMICOLON) | |
| lexer.skip_token (); | |
| } | |
| /* Skips the current token */ | |
| template <typename ManagedTokenSource> | |
| void | |
| Parser<ManagedTokenSource>::skip_token () | |
| { | |
| lexer.skip_token (); | |
| } | |
| /* Checks if current token has inputted id - skips it and returns true if so, | |
| * diagnoses an error and returns false otherwise. */ | |
| template <typename ManagedTokenSource> | |
| bool | |
| Parser<ManagedTokenSource>::skip_token (TokenId token_id) | |
| { | |
| return expect_token (token_id) != const_TokenPtr (); | |
| } | |
| /* Checks if current token is similar to inputted token - skips it and returns | |
| * true if so, diagnoses an error and returns false otherwise. */ | |
| template <typename ManagedTokenSource> | |
| bool | |
| Parser<ManagedTokenSource>::skip_token (const_TokenPtr token) | |
| { | |
| return expect_token (token) != const_TokenPtr (); | |
| } | |
| /* Checks if current token has inputted id - skips it and returns true if so, | |
| * returns false otherwise without diagnosing an error */ | |
| template <typename ManagedTokenSource> | |
| bool | |
| Parser<ManagedTokenSource>::maybe_skip_token (TokenId token_id) | |
| { | |
| if (lexer.peek_token ()->get_id () != token_id) | |
| return false; | |
| else | |
| return skip_token (token_id); | |
| } | |
| /* Checks the current token - if id is same as expected, skips and returns it, | |
| * otherwise diagnoses error and returns null. */ | |
| template <typename ManagedTokenSource> | |
| const_TokenPtr | |
| Parser<ManagedTokenSource>::expect_token (TokenId token_id) | |
| { | |
| const_TokenPtr t = lexer.peek_token (); | |
| if (t->get_id () == token_id) | |
| { | |
| lexer.skip_token (); | |
| return t; | |
| } | |
| else | |
| { | |
| Error error (t->get_locus (), "expecting %qs but %qs found", | |
| get_token_description (token_id), | |
| t->get_token_description ()); | |
| add_error (std::move (error)); | |
| return const_TokenPtr (); | |
| } | |
| } | |
| /* Checks the current token - if same as expected, skips and returns it, | |
| * otherwise diagnoses error and returns null. */ | |
| template <typename ManagedTokenSource> | |
| const_TokenPtr | |
| Parser<ManagedTokenSource>::expect_token (const_TokenPtr token_expect) | |
| { | |
| const_TokenPtr t = lexer.peek_token (); | |
| if (t->get_id () == token_expect->get_id () | |
| && (!t->should_have_str () || t->get_str () == token_expect->get_str ())) | |
| { | |
| lexer.skip_token (); | |
| return t; | |
| } | |
| else | |
| { | |
| Error error (t->get_locus (), "expecting %qs but %qs found", | |
| token_expect->get_token_description (), | |
| t->get_token_description ()); | |
| add_error (std::move (error)); | |
| return const_TokenPtr (); | |
| } | |
| } | |
| // Skips all tokens until EOF or }. Don't use. | |
| template <typename ManagedTokenSource> | |
| void | |
| Parser<ManagedTokenSource>::skip_after_end () | |
| { | |
| const_TokenPtr t = lexer.peek_token (); | |
| while (t->get_id () != END_OF_FILE && t->get_id () != RIGHT_CURLY) | |
| { | |
| lexer.skip_token (); | |
| t = lexer.peek_token (); | |
| } | |
| if (t->get_id () == RIGHT_CURLY) | |
| { | |
| lexer.skip_token (); | |
| } | |
| } | |
| /* A slightly more aware error-handler that skips all tokens until it reaches | |
| * the end of the block scope (i.e. when left curly brackets = right curly | |
| * brackets). Note: assumes currently in the middle of a block. Use | |
| * skip_after_next_block to skip based on the assumption that the block | |
| * has not been entered yet. */ | |
| template <typename ManagedTokenSource> | |
| void | |
| Parser<ManagedTokenSource>::skip_after_end_block () | |
| { | |
| const_TokenPtr t = lexer.peek_token (); | |
| int curly_count = 1; | |
| while (curly_count > 0 && t->get_id () != END_OF_FILE) | |
| { | |
| switch (t->get_id ()) | |
| { | |
| case LEFT_CURLY: | |
| curly_count++; | |
| break; | |
| case RIGHT_CURLY: | |
| curly_count--; | |
| break; | |
| default: | |
| break; | |
| } | |
| lexer.skip_token (); | |
| t = lexer.peek_token (); | |
| } | |
| } | |
| /* Skips tokens until the end of the next block. i.e. assumes that the block | |
| * has not been entered yet. */ | |
| template <typename ManagedTokenSource> | |
| void | |
| Parser<ManagedTokenSource>::skip_after_next_block () | |
| { | |
| const_TokenPtr t = lexer.peek_token (); | |
| // initial loop - skip until EOF if no left curlies encountered | |
| while (t->get_id () != END_OF_FILE && t->get_id () != LEFT_CURLY) | |
| { | |
| lexer.skip_token (); | |
| t = lexer.peek_token (); | |
| } | |
| // if next token is left, skip it and then skip after the block ends | |
| if (t->get_id () == LEFT_CURLY) | |
| { | |
| lexer.skip_token (); | |
| skip_after_end_block (); | |
| } | |
| // otherwise, do nothing as EOF | |
| } | |
| /* Skips all tokens until ] (the end of an attribute) - does not skip the ] | |
| * (as designed for attribute body use) */ | |
| template <typename ManagedTokenSource> | |
| void | |
| Parser<ManagedTokenSource>::skip_after_end_attribute () | |
| { | |
| const_TokenPtr t = lexer.peek_token (); | |
| while (t->get_id () != RIGHT_SQUARE && t->get_id () != END_OF_FILE) | |
| { | |
| lexer.skip_token (); | |
| t = lexer.peek_token (); | |
| } | |
| // Don't skip the RIGHT_SQUARE token | |
| } | |
| // Returns true if the next token is END, ELSE, or EOF; | |
| template <typename ManagedTokenSource> | |
| bool | |
| Parser<ManagedTokenSource>::done_end_or_else () | |
| { | |
| const_TokenPtr t = lexer.peek_token (); | |
| return (t->get_id () == RIGHT_CURLY || t->get_id () == ELSE | |
| || t->get_id () == END_OF_FILE); | |
| } | |
| // Returns true if the next token is END or EOF. | |
| template <typename ManagedTokenSource> | |
| bool | |
| Parser<ManagedTokenSource>::done_end () | |
| { | |
| const_TokenPtr t = lexer.peek_token (); | |
| return (t->get_id () == RIGHT_CURLY || t->get_id () == END_OF_FILE); | |
| } | |
| } // namespace Rust |