use thiserror::Error; use tracing::error; use crate::{ environment::{Environment, EnvironmentError}, expression::Expression, statement::Statement, token::{Literal, Token, TokenType}, value::Value, }; #[derive(Error, Debug)] pub enum InterpreterError { #[error("[line {0}] MINUS unary expression expects a number on the right")] UnaryExpressionNotANumber(usize), #[error("[line {0}] unknown unary operator: {1}")] UnaryOperatorUnknown(usize, String), #[error("[line {0}] unknown binary operator: {1}")] BinaryOperatorUnknown(usize, String), #[error("[line {0}] left or right is not a number.")] BinaryExpressionNeedsNumber(usize), #[error("[line {0}] left or right is neither a number nor string.")] BinaryExpressionNeedsNumberOrString(usize), #[error("{0}")] UndefinedVariable(EnvironmentError), } /// Interpreter for the Lox language. #[derive(Default, Debug)] pub struct Interpreter { environment: Environment, } impl Interpreter { /// Try to evaluate an expression and return its result. pub fn run(&mut self, statements: Vec) -> Result<(), InterpreterError> { for stmt in statements { match self.execute(stmt) { Ok(_) => {} Err(e) => error!("{e}"), }; } Ok(()) } ///Execute a statement. fn execute(&mut self, statement: Statement) -> Result<(), InterpreterError> { match statement { Statement::Block(statements) => { let sub_env = Environment::with_enclosing(self.environment.clone()); self.block(statements, sub_env)? } Statement::Print(expression) => self.print_statement(expression)?, Statement::Expression(expression) => { self.evaluate(expression)?; } Statement::Var { name, initializer } => self.var_statement(name, *initializer)?, }; Ok(()) } /// Execute all statements within a block, using a new environment (with the old one as the /// enclosing one). fn block( &mut self, statements: Vec, environment: Environment, ) -> Result<(), InterpreterError> { let prev_env = &self.environment.clone(); self.environment = environment; for stmt in statements { if let Err(e) = self.execute(stmt) { error!("{e}"); } } self.environment = prev_env.clone(); Ok(()) } /// Evaluate an expression and return its value. fn evaluate(&mut self, expression: Expression) -> Result { match expression { Expression::Literal { value } => self.literal(value), Expression::Grouping { expression } => self.grouping(*expression), Expression::Unary { operator: op, right, } => self.unary(op, *right), Expression::Binary { left, operator, right, } => self.binary(*left, operator, *right), Expression::Variable { name } => self.var_expression(&name), Expression::Assign { name, value } => self.assign(&name, *value), } } /// Evaluate an expression and print its value to stdout. fn print_statement(&mut self, expression: Expression) -> Result<(), InterpreterError> { let value = self.evaluate(expression)?; println!("{value}"); Ok(()) } /// Initialize a variable with an initializer expression or nil. fn var_statement( &mut self, name: Token, initializer: Option, ) -> Result<(), InterpreterError> { let value = if let Some(initializer) = initializer { self.evaluate(initializer) } else { Ok(Value::Nil) }?; self.environment.define(name.lexeme, value); Ok(()) } /// Assign the value of an expression to a variable. fn assign(&mut self, name: &Token, value: Expression) -> Result { let value = self.evaluate(value)?; self.environment .assign(name, value.clone()) .map_err(InterpreterError::UndefinedVariable)?; Ok(value) } /// Convert the literal value into a Value. fn literal(&self, literal: Literal) -> Result { Ok(literal.into()) } /// Evaluate the inner expression. fn grouping(&mut self, inner: Expression) -> Result { self.evaluate(inner) } /// Evaluate the expression on the right and use its result when evaluating the unary operator. fn unary(&mut self, op: Token, right: Expression) -> Result { let right = self.evaluate(right)?; match op.token_type { TokenType::Minus => { if let Value::Number(val) = right { Ok(Value::Number(-val)) } else { Err(InterpreterError::UnaryExpressionNotANumber(op.line)) } } TokenType::Bang => Ok(Value::Boolean(!right.is_truthy())), _ => Err(InterpreterError::UnaryOperatorUnknown(op.line, op.lexeme)), } } /// Get the value of a variable. fn var_expression(&mut self, name: &Token) -> Result { self.environment .get(name) .map_err(InterpreterError::UndefinedVariable) } /// Calculate number operations. fn number_op(&self, left: f64, op: TokenType, right: f64) -> f64 { match op { TokenType::Minus => left - right, TokenType::Plus => left + right, TokenType::Slash => left / right, TokenType::Star => left * right, _ => unreachable!(), } } /// Calculate boolean operations. fn boolean_op(&self, left: f64, op: TokenType, right: f64) -> bool { match op { TokenType::Greater => left > right, TokenType::GreaterEqual => left >= right, TokenType::Less => left < right, TokenType::LessEqual => left <= right, _ => unreachable!(), } } /// Evaluate the left and right expressions (in that order) and then combine them with the /// specified operator. fn binary( &mut self, left: Expression, op: Token, right: Expression, ) -> Result { let left = self.evaluate(left)?; let right = self.evaluate(right)?; match op.token_type { TokenType::Minus | TokenType::Slash | TokenType::Star | TokenType::Plus => { if let (Value::Number(left), Value::Number(right)) = (left.clone(), right.clone()) { Ok(Value::Number(self.number_op(left, op.token_type, right))) } else if let (Value::String(left), Value::String(right)) = (left, right) { Ok(Value::String(format!("{}{}", left.clone(), right.clone()))) } else { Err(InterpreterError::BinaryExpressionNeedsNumberOrString( op.line, )) } } TokenType::Greater | TokenType::GreaterEqual | TokenType::Less | TokenType::LessEqual => { if let (Value::Number(left), Value::Number(right)) = (left, right) { Ok(Value::Boolean(self.boolean_op(left, op.token_type, right))) } else { Err(InterpreterError::BinaryExpressionNeedsNumber(op.line)) } } TokenType::BangEqual => Ok(Value::Boolean(left != right)), TokenType::EqualEqual => Ok(Value::Boolean(left == right)), _ => Err(InterpreterError::BinaryOperatorUnknown(op.line, op.lexeme)), } } }