Files
gcc-reflection/gcc/rust/parse/rust-parse-impl-utils.hxx
2026-01-02 09:56:11 +01:00

253 lines
6.8 KiB
C++

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