brainterpreter 0.1.1

An interpreter for a Bauble toy programming language
Documentation
use log::trace;

use crate::ast::Statement;
use crate::lexer::token::Token;
use crate::lexer::SourceToken;
use crate::parser::{Parser, ParsingError};

impl<T> Parser<T>
where
    T: Iterator<Item = SourceToken>,
{
    pub fn statement(&mut self) -> Result<Statement, ParsingError> {
        if let Token::Identifier(_) = self.peek() {
            return self.expression_statement();
        }
        match self.advance() {
            Token::Print => self.print_statement(),
            Token::LeftCurly => self.block_statement(),
            Token::Let => self.variable_definition(),
            Token::Fun => self.function_definition(),
            Token::If => self.if_statement(),
            Token::While => self.while_statement(),
            Token::Return => {
                let expr = self.expression()?;
                self.consume(&Token::Semicolon)?;
                Ok(Statement::Return(expr))
            }
            _ => Err(ParsingError::Unknown(self.last_position())),
        }
    }

    fn variable_definition(&mut self) -> Result<Statement, ParsingError> {
        trace!("Parsing variable declaration");
        let token = self.advance();
        trace!("Variable declaration token: {:?}", token);
        let name = match token {
            Token::Identifier(name) => name,
            _ => {
                return Err(ParsingError::MissingToken {
                    position: self.last_position(),
                    expected: Token::Identifier("identifier".to_string()),
                    actual: token.clone(),
                })
            }
        };

        let def = if self.advance_if(Token::Equal) {
            let expr = self.expression()?;
            Ok(Statement::DefineVariable(name, expr))
        } else {
            Ok(Statement::DeclareVariable(name))
        };
        self.consume(&Token::Semicolon)?;
        def
    }

    fn function_definition(&mut self) -> Result<Statement, ParsingError> {
        trace!("Parsing function declaration");
        let token = self.advance();
        trace!("Function declaration token: {:?}", token);
        let name = match token {
            Token::Identifier(name) => name,
            _ => {
                return Err(ParsingError::UnexpectedToken(
                    token.clone(),
                    self.last_position(),
                ))
            }
        };

        let mut parameters = vec![];
        self.consume(&Token::LeftParen)?;
        if let Token::Identifier(name) = self.peek() {
            parameters.push(name.clone());
            self.advance();
        }
        while self.advance_if(Token::Comma) {
            if let Token::Identifier(name) = self.peek() {
                parameters.push(name.clone());
                self.advance();
            }
        }
        self.consume(&Token::RightParen)?;
        self.consume(&Token::LeftCurly)?;
        let body = self.block_statement()?;
        Ok(Statement::Function(name, parameters, Box::new(body)))
    }

    fn block_statement(&mut self) -> Result<Statement, ParsingError> {
        trace!("Parsing block statement");
        let mut statements = Vec::new();
        loop {
            match self.peek() {
                Token::RightCurly | Token::EndOfFile => {
                    break;
                }
                _ => {}
            }
            statements.push(self.statement()?);
        }
        self.consume(&Token::RightCurly)?;
        Ok(Statement::Block(statements))
    }

    fn if_statement(&mut self) -> Result<Statement, ParsingError> {
        trace!("Parsing if statement");
        self.consume(&Token::LeftParen)?;
        let condition = self.expression()?;
        self.consume(&Token::RightParen)?;
        let then_branch = self.statement()?;
        let else_branch = if self.advance_if(Token::Else) {
            Some(Box::new(self.statement()?))
        } else {
            None
        };
        Ok(Statement::If(condition, Box::new(then_branch), else_branch))
    }

    fn while_statement(&mut self) -> Result<Statement, ParsingError> {
        trace!("Parsing while statement");
        self.consume(&Token::LeftParen)?;
        let condition = self.expression()?;
        self.consume(&Token::RightParen)?;
        let body = self.statement()?;
        Ok(Statement::While(condition, Box::new(body)))
    }

    fn print_statement(&mut self) -> Result<Statement, ParsingError> {
        trace!("Parsing print statement");
        let expr = self.expression()?;
        self.consume(&Token::Semicolon)?;
        Ok(Statement::Print(expr))
    }

    fn expression_statement(&mut self) -> Result<Statement, ParsingError> {
        trace!("Parsing expression statement");
        let expr = self.expression()?;
        self.consume(&Token::Semicolon)?;
        Ok(Statement::Expression(expr))
    }
}

#[cfg(test)]
mod tests {
    use crate::ast::{BinaryOperator, Expression, Statement};
    use crate::lexer::Lexer;

    use super::*;

    #[test]
    fn variable_declaration() {
        let mut parser = Parser::new(Lexer::new("let a;"));
        let statement = parser.statement().unwrap();
        assert_eq!(statement, Statement::DeclareVariable("a".to_string()));
    }

    #[test]
    fn variable_assignment() {
        let mut parser = Parser::new(Lexer::new("a = 1;"));
        let statement = parser.statement().unwrap();
        assert_eq!(
            statement,
            Statement::Expression(Expression::AssignVariable(
                "a".to_string(),
                Box::new(Expression::number(1))
            ))
        );
    }

    #[test]
    fn variable_definition() {
        let mut parser = Parser::new(Lexer::new("let a = 1;"));
        let statement = parser.statement().unwrap();
        assert_eq!(
            statement,
            Statement::DefineVariable("a".to_string(), Expression::number(1))
        );
    }

    #[test]
    fn function_definition() {
        let mut parser = Parser::new(Lexer::new("fun a() {}"));
        let statement = parser.statement().unwrap();
        assert_eq!(
            statement,
            Statement::function("a", &[], Statement::Block(vec![]))
        );
    }

    #[test]
    fn function_definition_with_parameters() {
        let mut parser = Parser::new(Lexer::new("fun a(b, c) {}"));
        let statement = parser.statement().unwrap();
        assert_eq!(
            statement,
            Statement::function("a", &["b", "c"], Statement::Block(vec![]))
        );
    }

    #[test]
    fn if_statement() {
        let mut parser = Parser::new(Lexer::new("if (a == 10) { }"));
        let statement = parser.statement().unwrap();
        assert_eq!(
            statement,
            Statement::if_statement(
                Expression::binary(
                    BinaryOperator::Equal,
                    Expression::variable("a"),
                    Expression::number(10)
                ),
                Statement::Block(vec![]),
            )
        );
    }

    #[test]
    fn if_else_statement() {
        let mut parser = Parser::new(Lexer::new("if (a == 10) { } else {}"));
        let statement = parser.statement().unwrap();
        assert_eq!(
            statement,
            Statement::if_else_statement(
                Expression::binary(
                    BinaryOperator::Equal,
                    Expression::variable("a"),
                    Expression::number(10)
                ),
                Statement::Block(vec![]),
                Statement::Block(vec![])
            )
        );
    }

    #[test]
    fn while_statement() {
        let mut parser = Parser::new(Lexer::new("while (i > 0) { }"));
        let statement = parser.statement().unwrap();
        assert_eq!(
            statement,
            Statement::while_loop(
                Expression::binary(
                    BinaryOperator::Greater,
                    Expression::variable("i"),
                    Expression::number(0)
                ),
                Statement::Block(vec![])
            )
        );
    }

    #[test]
    fn print_statement() {
        let mut parser = Parser::new(Lexer::new("print 1;"));
        let statement = parser.statement().unwrap();
        assert_eq!(statement, Statement::Print(Expression::number(1)));
    }
}