ralix 0.2.0

A simple, type-safe, tree walking interpreter
use std::path::Path;

use crate::{Lexer, Program, SymbolTable, Token};

mod error;
mod expressions;
mod statements;
mod types;

pub use error::*;

pub struct Parser<'src> {
    current_token: Token,
    peek_token: Token,

    lexer: Lexer<'src>,

    symbol_table: &'src mut SymbolTable,
    working_directory: &'src Path,
}

impl<'src> Parser<'src> {
    pub fn new(
        lexer: Lexer<'src>,
        symbol_table: &'src mut SymbolTable,
        working_directory: &'src Path,
    ) -> Self {
        let mut parser = Parser {
            lexer,

            peek_token: Token::default(),
            current_token: Token::default(),

            symbol_table,

            working_directory,
        };

        parser.next_token();
        parser.next_token();

        parser
    }

    pub fn parse_program(&mut self) -> Result<Program, ProgramParseError> {
        let mut statements = Vec::new();
        let mut errors = Vec::new();

        while !matches!(self.current_token, Token::EOF) {
            match self.parse_statement() {
                Ok(stmt) => statements.push(stmt),
                Err(err) => errors.push(err),
            }

            self.consume_peek_token(Token::SemiColon);

            self.next_token();
        }

        if !errors.is_empty() {
            Err(ProgramParseError::new(errors))
        } else {
            Ok(Program { statements })
        }
    }
}

impl Parser<'_> {
    fn next_token(&mut self) {
        self.current_token = self.peek_token.clone();
        self.peek_token = self.lexer.next_token();
    }

    fn expect_ident(&mut self) -> ParserResult<()> {
        self.next_token();
        if !matches!(self.current_token, Token::Ident(_)) {
            return Err(ParserDiagnostic::IsNotIdentifier(
                self.current_token.clone(),
            ));
        }

        Ok(())
    }

    fn expect_token(&mut self, token: Token) -> ParserResult<()> {
        self.next_token();
        if token != self.current_token {
            return Err(ParserDiagnostic::SyntaxError {
                expected: token,
                got: self.current_token.clone(),
            });
        }
        self.next_token();

        Ok(())
    }

    fn is_current_token(&self, token: Token) -> bool {
        self.current_token == token
    }

    fn is_peek_token(&self, token: Token) -> bool {
        self.peek_token == token
    }

    fn consume_peek_token(&mut self, token: Token) {
        if self.is_peek_token(token) {
            self.next_token();
        }
    }

    fn consume_current_token(&mut self, token: Token) -> bool {
        if self.is_current_token(token) {
            self.next_token();
            true
        } else {
            false
        }
    }

    fn skip_peek_token(&mut self, token: Token) {
        if self.is_peek_token(token) {
            self.next_token();
            self.next_token();
        }
    }
}