skullbrain-parser 0.1.0

Parses skullbrain tokens into a concrete syntax tree (CST).
Documentation
use skullbrain_diagnostics::{EmitDiagnostics, ParseError};
use skullbrain_lexer::{DeclarationKind, TokenKind};

use crate::{state::ConcreteSyntaxTreeBuilder, Diagnostics, ParserState, SyntaxKind};

impl<'input, D: Diagnostics, C: ConcreteSyntaxTreeBuilder> ParserState<'input, D, C> {
    pub(super) fn parse_variable(&mut self) {
        self.start_node(SyntaxKind::VariableDeclaration);

        self.parse_optional_modifiers();
        self.parse_variable_keyword();
        self.skip_trivia();

        self.parse_variable_ident_type();
        self.skip_trivia();

        self.parse_only_assignable_expression();

        self.finish_node();
    }

    fn parse_variable_ident_type(&mut self) {
        if self.peek_sequence(Self::peek_sequence_for_single_function_parameter) {
            // NOTE: Function Parameter follows the same format of "<ident> is <type>" as the var-delc
            self.parse_single_function_parameter();
            return;
        }

        if self.peek().is_some_and(|i| i.kind().is_ident()) {
            self.parse_ident();
            return;
        }

        let diagnostic_details = self.diagnostic_details();
        // Emit MissingVariableName
        let error = ParseError::expected_variable_name_before();
        self.emit_diagnostic(error, diagnostic_details);
    }

    fn parse_variable_keyword(&mut self) {
        let Some(item) = self.next() else {
            unreachable!()
        };

        match item.kind() {
            TokenKind::Declaration(DeclarationKind::VariableDeclaration { is_mutable }) => {
                let kind = if *is_mutable {
                    SyntaxKind::MutableVariableKeyword
                } else {
                    SyntaxKind::ImmutableVariableKeyword
                };

                self.token(kind, item);
            }
            _ => unreachable!(),
        }
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_variable() {
        crate::test::create_parsing_test("variable/*.skull", |state| {
            state.parse_variable();
        });
    }
}