skullbrain-parser 0.1.0

Parses skullbrain tokens into a concrete syntax tree (CST).
Documentation
use super::*;

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

        self.parse_if_expr();
        self.skip_trivia();

        while self.peek().is_some_and(|i| is_else_kw(i.kind())) {
            self.skip_trivia();
            self.parse_else_or_else_if();
            self.skip_trivia();
        }

        self.finish_node();
    }

    pub(super) fn parse_else_with_missing_if(&mut self) {
        self.start_node(SyntaxKind::IfElse);
        self.emit_missing_if_stmt();
        self.parse_else_or_else_if();
        self.finish_node();
    }

    // ----------

    fn parse_if_expr(&mut self) {
        self.start_node(SyntaxKind::If);
        self.parse_token(SyntaxKind::Keyword);

        self.skip_trivia();
        self.parse_condition_and_body_for_if_else();
        self.finish_node();
    }

    fn parse_else_or_else_if(&mut self) {
        self.start_node(SyntaxKind::Else);
        self.parse_token(SyntaxKind::Keyword);
        self.skip_trivia();

        if self
            .peek()
            .is_some_and(|i| i.kind().is(&TokenKind::ControlFlow(ControlFlowKind::If)))
        {
            self.skip_trivia();
            self.parse_token(SyntaxKind::Keyword);
        }

        self.skip_trivia();
        self.parse_condition_and_body_for_if_else();
        self.finish_node();
    }

    fn parse_condition_and_body_for_if_else(&mut self) {
        self.parse_condition_and_body_until(|k| is_else_kw(k));
    }

    fn emit_missing_if_stmt(&mut self) {
        let diagnostic_details = self.diagnostic_details();
        let error = ParseError::missing_if_statement();
        self.emit_diagnostic(error, diagnostic_details);
    }
}

fn is_else_kw(k: &TokenKind) -> bool {
    k.is(&TokenKind::ControlFlow(ControlFlowKind::Else))
}

mod test {
    #[test]
    fn test_if_else() {
        crate::test::create_parsing_test("if_else/if_else*.skull", |state| {
            state.parse_if_else();
        });
    }

    #[test]
    fn test_missing_if() {
        crate::test::create_parsing_test("if_else/missing_if*.skull", |state| {
            state.parse_else_with_missing_if();
        });
    }
}