// 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 { // "Unexpected token" panic mode - flags gcc error at unexpected token // TODO: seems to be unused, remove? template void Parser::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 void Parser::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 void Parser::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 bool Parser::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 bool Parser::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 bool Parser::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 const_TokenPtr Parser::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 const_TokenPtr Parser::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 void Parser::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 void Parser::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 void Parser::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 void Parser::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 bool Parser::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 bool Parser::done_end () { const_TokenPtr t = lexer.peek_token (); return (t->get_id () == RIGHT_CURLY || t->get_id () == END_OF_FILE); } } // namespace Rust