skullbrain-parser 0.1.0

Parses skullbrain tokens into a concrete syntax tree (CST).
Documentation
mod assignable;
mod basic;
mod class;
mod control_flow;
mod enumz;
mod func;
mod if_else;
mod import;
mod loops;
mod matchz;
mod modifier;
mod possible_call;
mod pratt;
mod throw_error;
mod traits;
mod try_catch;
mod ty;
mod type_alias;
mod utilities;
mod variable;

// TODOs:
// - Improve diagnostic messages (where possible)
// - Maybe use identation to improve delimiter-end/start

use skullbrain_diagnostics::{EmitDiagnostics, ParseError};
use skullbrain_lexer::{ControlFlowKind, DeclarationKind, PunctuationKind, TokenKind};

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

impl<'input, D: Diagnostics, C: ConcreteSyntaxTreeBuilder> ParserState<'input, D, C> {
    fn parse_optional_expression(&mut self) {
        if self.peek().is_some() {
            self.parse_expression();
        }
    }

    pub(crate) fn parse_expression(&mut self) {
        self.parse_with_binding_power(0);

        if self.peek_raw().is_some_and(|i| is_dot(i.kind())) {
            self.parse_raw_token(SyntaxKind::SemiColon);
        }
    }

    fn __parse_actual_expression(&mut self) {
        self.skip_trivia();
        match self.peek() {
            None => self.emit_expected_expression_eof(),
            Some(item) => match item.kind() {
                TokenKind::Unknown => self.parse_unknown(),
                TokenKind::Literial(_) => self.parse_literal(),
                TokenKind::Ident => self.parse_possible_call_expr_or_ident_only(),
                TokenKind::ControlFlow(ControlFlowKind::Throw) => self.parse_throw_error(),
                TokenKind::ControlFlow(ControlFlowKind::Break) => self.parse_break_stmt(),
                TokenKind::ControlFlow(ControlFlowKind::Continue) => self.parse_continue_stmt(),
                TokenKind::ControlFlow(ControlFlowKind::Return) => self.parse_return_stmt(),
                TokenKind::ControlFlow(ControlFlowKind::While) => self.parse_while_loop(),
                TokenKind::ControlFlow(ControlFlowKind::Try) => self.parse_try_catch(),
                TokenKind::ControlFlow(ControlFlowKind::Catch) => {
                    self.parse_catch_with_missing_try()
                }
                TokenKind::ControlFlow(ControlFlowKind::If) => self.parse_if_else(),
                TokenKind::ControlFlow(ControlFlowKind::Else) => self.parse_else_with_missing_if(),
                TokenKind::ControlFlow(ControlFlowKind::ForLoopOpen) => self.parse_for_loop(),
                TokenKind::ControlFlow(ControlFlowKind::ForLoopClose) => {
                    self.parse_for_loop_with_missing_open()
                }
                TokenKind::ControlFlow(ControlFlowKind::Match) => self.parse_match(),
                TokenKind::ControlFlow(ControlFlowKind::MatchArmCondition) => {
                    self.parse_match_cond()
                }
                TokenKind::ControlFlow(ControlFlowKind::MatchArmDefault) => {
                    self.parse_match_default_cond()
                }

                TokenKind::Declaration(DeclarationKind::VariableDeclaration { .. }) => {
                    self.parse_variable()
                }
                TokenKind::Punctuation(PunctuationKind::OpenBrace) => {
                    self.parse_brace_with_expression()
                }
                TokenKind::Punctuation(PunctuationKind::CloseBrace) => {
                    self.parse_brace_with_expression()
                }
                TokenKind::Punctuation(PunctuationKind::OpenParen) => {
                    self.parse_parenthesis_with_expression()
                }
                TokenKind::Punctuation(PunctuationKind::CloseParen) => {
                    self.parse_parenthesis_with_expression()
                }

                TokenKind::Punctuation(PunctuationKind::Arrow) => {
                    self.parse_token(SyntaxKind::Arrow);
                }

                TokenKind::Punctuation(PunctuationKind::Colon) => {
                    self.parse_token(SyntaxKind::Colon);
                }
                TokenKind::Punctuation(PunctuationKind::Comma) => {
                    self.parse_token(SyntaxKind::Comma);
                }

                TokenKind::Declaration(DeclarationKind::Import) => self.parse_import_expression(),
                TokenKind::Declaration(DeclarationKind::Alias) => self.parse_type_alias(),
                TokenKind::Declaration(DeclarationKind::Function) => self.parse_function_delc(),
                TokenKind::Declaration(DeclarationKind::Trait) => self.parse_trait_delc(),
                TokenKind::Declaration(DeclarationKind::TraitImpl) => self.parse_trait_impl(),
                TokenKind::Declaration(DeclarationKind::Class) => self.parse_class_delc(),
                TokenKind::Declaration(DeclarationKind::Enum) => self.parse_enum_delc(),
                TokenKind::Declaration(DeclarationKind::EnumVariant) => self.parse_enum_variant(),
                TokenKind::Modifier(_) => self.wrap_modifiers_if_needed(),

                TokenKind::Whitespace
                | TokenKind::SingleLineComment
                | TokenKind::MultiLineComment { .. }
                | TokenKind::Punctuation(PunctuationKind::Dot)
                | TokenKind::Operator(_) => unreachable!(),
            },
        }
    }

    fn wrap_modifiers_if_needed(&mut self) {
        let accepts_modifiers = self.peek_sequence(|peekable| {
            skip_modifier_tokens(peekable);
            peekable
                .peek_next()
                .and_then(|i| next_token_accepts_modifiers(i))
        });

        match accepts_modifiers {
            Some(delc) => match delc {
                DeclarationKind::Alias => self.parse_type_alias(),
                DeclarationKind::Function => self.parse_function_delc(),
                DeclarationKind::Trait => self.parse_trait_delc(),
                DeclarationKind::Class => self.parse_class_delc(),
                DeclarationKind::Enum => self.parse_enum_delc(),
                _ => unreachable!(),
            },
            None => {
                self.parse_optional_modifiers();
            }
        }
    }
}

fn next_token_accepts_modifiers(i: &crate::state::PositionedToken) -> Option<DeclarationKind> {
    match i.kind().declaration_ref() {
        Some(d)
            if d.is_alias() || d.is_function() || d.is_trait() || d.is_class() || d.is_enum() =>
        {
            Some(d.clone())
        }
        _ => None,
    }
}

fn skip_modifier_tokens(peekable: &mut PeekSequence) {
    while peekable.peek_next().is_some_and(|i| i.kind().is_modifier()) {}
}

impl<'input, D: Diagnostics, C: ConcreteSyntaxTreeBuilder> ParserState<'input, D, C> {
    fn emit_expected_expression_eof(&mut self) {
        let diagnostic_details = self.diagnostic_details();
        let error = ParseError::expected_expression_at();
        self.emit_diagnostic(error, diagnostic_details);
    }
}

fn is_dot(kind: &TokenKind) -> bool {
    kind.punctuation_ref().is_some_and(|k| k.is_dot())
}