use crate::{state::ConcreteSyntaxTreeBuilder, Diagnostics, ParserState, SyntaxKind};
use skullbrain_diagnostics::{EmitDiagnostics, ParseError};
use skullbrain_lexer::{OperatorKind, TokenKind};
impl<'input, D: Diagnostics, C: ConcreteSyntaxTreeBuilder> ParserState<'input, D, C> {
pub(super) fn parse_only_assignable_expression(&mut self) {
if self.peek().is_none_or(|i| !is_assignment(i.kind())) {
self.skip_trivia();
self.recover();
}
match self.peek() {
None => {
let error = if self.peek_raw().is_some() {
ERROR_BEFORE
} else {
ERROR_AT
};
self.emit_expected_assignment_token(error);
}
Some(item) if is_assignment(item.kind()) => {
let Some(item) = self.next() else {
unreachable!()
};
self.token(SyntaxKind::Assignment, item);
self.skip_trivia();
self.parse_expression();
}
Some(_) => {
self.emit_expected_assignment_token(ERROR_BEFORE);
self.parse_expression();
}
}
}
fn emit_expected_assignment_token(&mut self, error: ParseError) {
let diagnostic_details = self.diagnostic_details();
self.emit_diagnostic(error, diagnostic_details);
}
}
const ERROR_AT: ParseError = ParseError::expected_assignment_at();
const ERROR_BEFORE: ParseError =
ParseError::expected_token_before(TokenKind::Operator(OperatorKind::Assignment));
fn is_assignment(kind: &TokenKind) -> bool {
kind.operator_ref().is_some_and(|k| k.is_assignment())
}