use std::{cell::RefCell, collections::HashMap, rc::Rc}; use ordered_float::OrderedFloat; use thiserror::Error; use tracing::error; use crate::{ callable::CallingError, class::Class, environment::{Environment, EnvironmentError}, expression::Expression, function::{self, Function}, native_functions, statement::Statement, token::{Literal, Token, TokenType}, value::{CallableType, 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), #[error("line {0}: {1} is not callable.")] NotACallable(usize, Value), #[error("line {0}: {1}.")] FailedToCall(usize, CallingError), #[error("line {0}: only instances have fields.")] OnlyInstancesHaveFields(usize), #[error("line {0}: superclass must be a class.")] SuperclassNotClass(usize), #[error("line {0}: Undefined property '{1}'.")] UndefinedProperty(usize, String), #[error("{0}")] InstanceError(#[from] crate::instance::InstanceError), #[error("{0}")] EnvironmentError(#[from] crate::environment::EnvironmentError), } /// Interpreter for the Lox language. #[derive(Debug)] pub struct Interpreter { pub globals: Rc>, environment: Rc>, locals: HashMap, } /// Default configuration for the interpreter, with builtin native functions. impl Default for Interpreter { fn default() -> Self { let env: Rc> = Default::default(); { // add all native functions to global environment let mut env = env.borrow_mut(); for (name, fun) in native_functions::all() { env.define(name, fun); } } Self { globals: env.clone(), environment: env.clone(), locals: HashMap::new(), } } } 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(()) } pub fn resolve(&mut self, expression: Expression, depth: usize) { self.locals.insert(expression, depth); } ///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) => Ok(Some(self.evaluate(expression)?)), Statement::Var { name, initializer } => { self.var_statement(name, initializer.as_ref().as_ref()) } Statement::If { condition, then_branch, else_branch, } => { let else_branch = else_branch.as_ref().map(|x| *x.clone()); self.if_statement(condition, then_branch, else_branch.as_ref()) } Statement::While { condition, body } => self.while_statement(condition, body), Statement::Function { name, params, body } => { self.function_statement(name, params, body) } Statement::Return { keyword: _, value } => self.return_statement(value), Statement::Class { name, superclass, methods, } => self.class(name, superclass, methods), } } /// Execute all statements within a block, using a new environment (with the old one as the /// enclosing one). Immediately return the value if a Return Value is encountered after /// execution of a statement. pub fn block( &mut self, statements: &[Statement], environment: Environment, ) -> Result, InterpreterError> { let prev_env = self.environment.clone(); self.environment = Rc::new(RefCell::new(environment)); for stmt in statements { let execution = self.execute(stmt); match execution { Ok(x) => { if let Some(Value::Return(x)) = x { self.environment = prev_env.clone(); return Ok(Some(*x)); } } Err(e) => error!("{e}"), } } self.environment = prev_env.clone(); Ok(None) } fn class( &mut self, name: &Token, superclass: &Option, methods: &[Statement], ) -> Result, InterpreterError> { let superclass = if let Some(superclass) = superclass { let superclass = self.evaluate(superclass)?; if let Value::Callable((_, CallableType::Class(class))) = superclass { Some(class) } else { return Err(InterpreterError::SuperclassNotClass(name.line)); } } else { None }; self.environment .borrow_mut() .define(name.lexeme.clone(), Value::Nil); let old_env = self.environment.clone(); if let Some(ref superclass) = superclass { self.environment = Rc::new(RefCell::new(Environment::with_enclosing( self.environment.clone(), ))); self.environment.borrow_mut().define( "super".to_string(), Value::Callable(( Rc::new(superclass.clone()), CallableType::Class(superclass.clone()), )), ); } let mut class_methods: HashMap = HashMap::new(); for method in methods { if let Statement::Function { name, params, body } = method { let function = function::Function { name: name.clone(), is_initializer: name.lexeme == "init", params: params.clone(), body: body.clone(), closure: self.environment.clone(), }; class_methods.insert(name.lexeme.clone(), function); } } let class = Class::new(name.lexeme.clone(), superclass, class_methods); if class.superclass.is_some() { self.environment = old_env; } self.environment .borrow_mut() .assign( name, Value::Callable((Rc::new(class.clone()), CallableType::Class(class))), ) .map_err(InterpreterError::UndefinedVariable)?; Ok(None) } /// Evaluate an expression and return its value. fn evaluate(&mut self, expression: &Expression) -> Result { match expression { Expression::Literal { value } => self.literal(value.clone()), 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), Expression::Assign { name, value } => self.assign(name, value), Expression::Logical { left, operator, right, } => self.logical_expression(left, operator, right), Expression::Call { callee, paren, args, } => self.call(callee, paren, args), Expression::Get { object, name } => self.get(object, name), Expression::Set { object, name, value, } => self.set(object, name, value), Expression::This { keyword } => self.lookup_var(keyword, expression), Expression::Super { keyword, method } => self.super_expr(expression, keyword, method), } } /// Call a callable if it is one (meaning it starts with a LeftParen after an identifier), /// otherwise evaluate the expression. fn call( &mut self, callee: &Expression, paren: &Token, arg_expressions: &[Expression], ) -> Result { let callee = self.evaluate(callee)?; let mut args = Vec::new(); for arg in arg_expressions { args.push(self.evaluate(arg)?); } if let Value::Callable((f, _)) = callee { f.call(self, args) .map_err(|e| InterpreterError::FailedToCall(paren.line, e)) } else { Err(InterpreterError::NotACallable(paren.line, callee)) } } fn get(&mut self, object: &Expression, name: &Token) -> Result { match self.evaluate(object)? { Value::Instance(instance) => Ok(instance.borrow().get(name, instance.clone())?), _ => Err(InterpreterError::OnlyInstancesHaveFields(name.line)), } } fn set( &mut self, object: &Expression, name: &Token, value: &Expression, ) -> Result { match self.evaluate(object)? { Value::Instance(instance) => { let value = self.evaluate(value)?; instance.borrow_mut().set(name, value.clone()); Ok(value) } _ => Err(InterpreterError::OnlyInstancesHaveFields(name.line)), } } fn super_expr( &mut self, expression: &Expression, keyword: &Token, method: &Token, ) -> Result { if let Some(distance) = self.locals.get(expression) { let superclass = self.environment.borrow().get_at(*distance, keyword)?; let object = self.environment.borrow().get_at( *distance - 1, &Token { token_type: TokenType::This, lexeme: "this".to_string(), literal: Some(Literal::String("this".to_string())), line: 0, }, )?; let Value::Instance(instance) = object else { return Err(InterpreterError::SuperclassNotClass(keyword.line)); }; let Value::Callable((_, CallableType::Class(class))) = superclass else { return Err(InterpreterError::SuperclassNotClass(keyword.line)); }; if let Some(method) = class.find_method(&method.lexeme) { let method = method.bind(instance); Ok(Value::Callable((Rc::new(method), CallableType::Function))) } else { Err(InterpreterError::UndefinedProperty( keyword.line, method.lexeme.clone(), )) } } else { Err(InterpreterError::SuperclassNotClass(keyword.line)) } } /// Define a new function. fn function_statement( &mut self, name: &Token, params: &[Token], body: &[Statement], ) -> Result, InterpreterError> { let fn_name = name.lexeme.clone(); let fun = Function { name: name.clone(), is_initializer: false, params: params.to_vec(), body: body.to_vec(), closure: self.environment.clone(), }; self.environment.borrow_mut().define( fn_name, Value::Callable((Rc::new(fun), CallableType::Function)), ); Ok(None) } /// If the condition evaluates to truthy, execute the then branch, otherwise the else branch. fn if_statement( &mut self, condition: &Expression, then_branch: &Statement, else_branch: Option<&Statement>, ) -> Result, InterpreterError> { if self.evaluate(condition)?.is_truthy() { self.execute(then_branch) } else if let Some(else_branch) = else_branch { self.execute(else_branch) } else { Ok(None) } } /// 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(None) } /// Return a value from a statement. fn return_statement( &mut self, value: &Option, ) -> Result, InterpreterError> { Ok(match value { Some(x) => Some(Value::Return(Box::new(self.evaluate(x)?))), None => Some(Value::Return(Box::new(Value::Nil))), }) } /// Initialize a variable with an initializer expression or nil. fn var_statement( &mut self, name: &Token, initializer: Option<&Expression>, ) -> Result, InterpreterError> { let value = if let Some(initializer) = initializer { self.evaluate(initializer) } else { Ok(Value::Nil) }?; self.environment .borrow_mut() .define(name.lexeme.clone(), value); Ok(None) } /// Execute the body as long as the condition evaluates to true. fn while_statement( &mut self, condition: &Expression, body: &Statement, ) -> Result, InterpreterError> { while self.evaluate(condition)?.is_truthy() { self.execute(body)?; } Ok(None) } /// Assign the value of an expression to a variable. fn assign(&mut self, name: &Token, expression: &Expression) -> Result { let value = self.evaluate(expression)?; self.environment .borrow_mut() .assign(name, value.clone()) .map_err(InterpreterError::UndefinedVariable)?; if let Some(distance) = self.locals.get(expression) { self.environment .borrow_mut() .assign_at(*distance, name, value.clone()) .map_err(InterpreterError::UndefinedVariable)?; } else { self.globals .borrow_mut() .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 left and if the operator is Or and left is truthy or the operator is not Or and /// not leftis truthy short circuit and return left. Otherwise evaluate and return right. fn logical_expression( &mut self, left: &Expression, operator: &Token, right: &Expression, ) -> Result { let left = self.evaluate(left)?; let truthy = if operator.token_type == TokenType::Or { left.is_truthy() } else { !left.is_truthy() }; if truthy { Ok(left) } else { self.evaluate(right) } } /// 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.clone(), )), } } /// Get the value of a variable. fn var_expression( &mut self, name: &Token, expression: &Expression, ) -> Result { self.lookup_var(name, expression) } fn lookup_var( &mut self, name: &Token, expression: &Expression, ) -> Result { if let Some(distance) = self.locals.get(expression) { self.environment .borrow() .get_at(*distance, name) .map_err(InterpreterError::UndefinedVariable) } else { self.globals .borrow() .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(OrderedFloat(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.clone(), )), } } }