| // 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 |