rott/rottlib/src/parser/grammar/declarations/variable_declarators.rs
dkanus 588790b9b4 Refactor everything
Huge dump of refactored code. Still in the middle of the changes that
are to be squashed later in a one huge monster commit, because there is
no value in anything atomic here.
2026-04-05 20:32:11 +07:00

173 lines
6.3 KiB
Rust

//! Parsing of comma-separated variable declarator lists for
//! Fermented `UnrealScript`.
//!
//! Extends original `UnrealScript` by allowing array-size expressions and
//! declarator initializers.
#![allow(clippy::option_if_let_else)]
use std::ops::ControlFlow;
use crate::arena::ArenaVec;
use crate::ast::{AstSpan, OptionalExpression, VariableDeclarator, VariableDeclaratorRef};
use crate::lexer::{Token, TokenPosition};
use crate::parser::{ParseErrorKind, ParseResult, Parser, ResultRecoveryExt, SyncLevel};
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
enum VariableDeclaratorParseState {
ExpectingDeclarator,
ExpectingSeparator,
}
impl<'src, 'arena> Parser<'src, 'arena> {
/// Parses a comma-separated list of variable declarators.
///
/// Accepts optional array-size expressions and `=` initializers.
#[must_use]
pub(crate) fn parse_variable_declarators(
&mut self,
) -> ArenaVec<'arena, VariableDeclaratorRef<'src, 'arena>> {
use VariableDeclaratorParseState::{ExpectingDeclarator, ExpectingSeparator};
let mut declarators = self.arena.vec();
let mut parser_state = ExpectingDeclarator;
while let Some((next_token, next_token_position)) = self.peek_token_and_position() {
match (parser_state, next_token) {
(ExpectingDeclarator, Token::Semicolon) => {
self.report_error_here(ParseErrorKind::DeclEmptyVariableDeclarations);
return declarators;
}
(ExpectingDeclarator, Token::Comma) => {
if self
.recover_empty_variable_declarator(next_token_position)
.is_break()
{
return declarators;
}
}
(ExpectingDeclarator, _) => {
if self
.parse_variable_declarator_into(&mut declarators)
.is_break()
{
// Breaking means we've failed to parse declarator
self.report_error_here(ParseErrorKind::DeclEmptyVariableDeclarations);
break;
}
parser_state = ExpectingSeparator;
}
(ExpectingSeparator, Token::Comma) => {
self.advance();
parser_state = ExpectingDeclarator;
}
(ExpectingSeparator, Token::Semicolon) => break,
(ExpectingSeparator, _) => {
if self
.recover_missing_variable_declarator_separator(
next_token_position,
&mut declarators,
)
.is_break()
{
break;
}
}
}
self.ensure_forward_progress(next_token_position);
}
// In case of reaching EOF here, it does not matter if we emit
// an additional diagnostic.
// The caller is expected to report the more relevant enclosing error.
declarators
}
fn recover_empty_variable_declarator(
&mut self,
error_start_position: TokenPosition,
) -> ControlFlow<()> {
while self.peek_token() == Some(Token::Comma) {
self.advance();
}
self.make_error_here(ParseErrorKind::DeclEmptyVariableDeclarations)
.widen_error_span_from(error_start_position)
.report_error(self);
if matches!(self.peek_token(), Some(Token::Semicolon) | None) {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
}
fn parse_variable_declarator_into(
&mut self,
declarators: &mut ArenaVec<'arena, VariableDeclaratorRef<'src, 'arena>>,
) -> ControlFlow<()> {
if let Some(parsed_declarator) = self
.parse_variable_declarator()
.sync_error_until(self, SyncLevel::Statement)
.ok_or_report(self)
{
declarators.push(parsed_declarator);
ControlFlow::Continue(())
} else {
ControlFlow::Break(())
}
}
fn recover_missing_variable_declarator_separator(
&mut self,
error_start_position: TokenPosition,
declarators: &mut ArenaVec<'arena, VariableDeclaratorRef<'src, 'arena>>,
) -> ControlFlow<()> {
if let Some(parsed_declarator) = self
.parse_variable_declarator()
.widen_error_span_from(error_start_position)
.sync_error_until(self, SyncLevel::Statement)
.ok_or_report(self)
{
self.make_error_here(ParseErrorKind::DeclNoSeparatorBetweenVariableDeclarations)
.widen_error_span_from(error_start_position)
.report_error(self);
declarators.push(parsed_declarator);
ControlFlow::Continue(())
} else {
ControlFlow::Break(())
}
}
fn parse_variable_declarator(
&mut self,
) -> ParseResult<'src, 'arena, VariableDeclaratorRef<'src, 'arena>> {
let name = self.parse_identifier(ParseErrorKind::DeclBadVariableIdentifier)?;
let array_size = self.parse_optional_array_size();
let initializer = self.parse_optional_variable_initializer();
let span = AstSpan::range(name.0, self.last_consumed_position_or_start());
Ok(self.arena.alloc_node(
VariableDeclarator {
name,
initializer,
array_size,
},
span,
))
}
fn parse_optional_array_size(&mut self) -> OptionalExpression<'src, 'arena> {
if !self.eat(Token::LeftBracket) {
return None;
}
let array_size_expression = self.parse_expression();
self.expect(
Token::RightBracket,
ParseErrorKind::DeclExpectedRightBracketAfterArraySize,
)
.sync_error_at(self, SyncLevel::CloseBracket)
.report_error(self);
Some(array_size_expression)
}
fn parse_optional_variable_initializer(&mut self) -> OptionalExpression<'src, 'arena> {
self.eat(Token::Assign).then(|| self.parse_expression())
}
}