skullbrain-parser 0.1.0

Parses skullbrain tokens into a concrete syntax tree (CST).
Documentation
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())
}