use std::{cell::RefCell, rc::Rc}; use crate::{ ast, errors::{ErrorHandler, InterpreterError}, interpreter::{Environment, EnvironmentRef, Value}, tokens::{Token, TokenType}, }; use super::functions::Function; /// Evaluate an interpretable, returning its value. pub fn evaluate(err_hdl: &mut ErrorHandler, ast: &dyn Interpretable) -> Option<Value> { let env = Rc::new(RefCell::new(Environment::default())); match ast.interpret(&env) { Ok(v) => Some(v.result()), Err(e) => { e.report(err_hdl); None } } } /* ------- * * HELPERS * * ------- */ /// Interpreter flow control, which may be either a value, a loop break or a /// loop continuation. #[derive(Debug)] pub enum InterpreterFlowControl { Result(Value), Break(Option<String>), Continue(Option<String>), Return(Value), } impl InterpreterFlowControl { /// Return the result's value. If the flow control value does not represent /// a result, panic. pub(crate) fn result(self) -> Value { match self { Self::Result(v) => v, other => panic!("Result expected, {:?} found instead", other), } } /// Check whether a flow control value contains actual flow control /// information. pub(crate) fn is_flow_control(&self) -> bool { matches!(self, Self::Break(_) | Self::Continue(_) | Self::Return(_)) } } impl Default for InterpreterFlowControl { fn default() -> Self { Self::Result(Value::Nil) } } impl From<Value> for InterpreterFlowControl { fn from(value: Value) -> Self { Self::Result(value) } } /// A result returned by some part of the interpreter. pub type InterpreterResult = Result<InterpreterFlowControl, InterpreterError>; /// An Interpretable can be evaluated and will return a value. pub trait Interpretable { fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult; } /* ----------------------------- * * INTERPRETER FOR PROGRAM NODES * * ----------------------------- */ impl Interpretable for ast::ProgramNode { fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult { for stmt in self.0.iter() { stmt.interpret(environment)?; } Ok(InterpreterFlowControl::default()) } } /* ------------------------------- * * INTERPRETER FOR STATEMENT NODES * * ------------------------------- */ impl Interpretable for ast::StmtNode { fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult { match self { ast::StmtNode::VarDecl(name, expr) => self.on_var_decl(environment, name, expr), ast::StmtNode::FunDecl { name, params, body } => { self.on_fun_decl(environment, name, params, body) } ast::StmtNode::Expression(expr) => expr.interpret(environment), ast::StmtNode::Print(expr) => self.on_print(environment, expr), ast::StmtNode::Block(statements) => self.on_block(environment, statements), ast::StmtNode::If { condition, then_branch, else_branch, } => self.on_if_statement(environment, condition, then_branch, else_branch), ast::StmtNode::Loop { label, condition, body, after_body, } => self.on_loop_statement(environment, label, condition, body, after_body), ast::StmtNode::LoopControl { is_break, loop_name, } => self.on_loop_control_statemement(*is_break, loop_name), ast::StmtNode::Return { token: _, value } => { self.on_return_statement(environment, value) } } } } impl ast::StmtNode { /// Handle the `print` statement. fn on_print(&self, environment: &EnvironmentRef, expr: &ast::ExprNode) -> InterpreterResult { let value = expr.interpret(environment)?.result(); let output = match value { Value::Nil => String::from("nil"), Value::Boolean(true) => String::from("true"), Value::Boolean(false) => String::from("false"), Value::Number(n) => n.to_string(), Value::String(s) => s, Value::Callable(c) => c.borrow().to_string(), }; println!("{}", output); Ok(InterpreterFlowControl::default()) } /// Handle a variable declaration. fn on_var_decl( &self, environment: &EnvironmentRef, name: &Token, initializer: &Option<ast::ExprNode>, ) -> InterpreterResult { let variable = match initializer { Some(expr) => Some(expr.interpret(environment)?.result()), None => None, }; environment.borrow_mut().define(name, variable)?; Ok(InterpreterFlowControl::default()) } /// Handle a function declaration. fn on_fun_decl( &self, environment: &EnvironmentRef, name: &Token, params: &Vec<Token>, body: &Vec<ast::StmtNode>, ) -> InterpreterResult { let fun = Function::new(name, params, body); environment .borrow_mut() .define(name, Some(Value::Callable(fun)))?; Ok(InterpreterFlowControl::default()) } /// Execute the contents of a block. fn on_block(&self, environment: &EnvironmentRef, stmts: &[ast::StmtNode]) -> InterpreterResult { let child = Environment::create_child(environment); for stmt in stmts.iter() { let result = stmt.interpret(&child)?; if result.is_flow_control() { return Ok(result); } } Ok(InterpreterFlowControl::default()) } /// Execute an if statement. fn on_if_statement( &self, environment: &EnvironmentRef, condition: &ast::ExprNode, then_branch: &ast::StmtNode, else_branch: &Option<Box<ast::StmtNode>>, ) -> InterpreterResult { if condition.interpret(environment)?.result().is_truthy() { then_branch.interpret(environment) } else if let Some(else_stmt) = else_branch { else_stmt.interpret(environment) } else { Ok(InterpreterFlowControl::default()) } } /// Execute a while statement. fn on_loop_statement( &self, environment: &EnvironmentRef, label: &Option<Token>, condition: &ast::ExprNode, body: &ast::StmtNode, after_body: &Option<Box<ast::StmtNode>>, ) -> InterpreterResult { let ln = label.as_ref().map(|token| token.lexeme.clone()); while condition.interpret(environment)?.result().is_truthy() { let result = body.interpret(environment)?; match &result { InterpreterFlowControl::Result(_) => (), InterpreterFlowControl::Continue(lv) if lv == &ln => (), InterpreterFlowControl::Break(lv) if lv == &ln => break, _ => return Ok(result), } if let Some(stmt) = after_body { let result = stmt.interpret(environment)?; match &result { InterpreterFlowControl::Result(_) => (), InterpreterFlowControl::Continue(lv) if lv == &ln => (), InterpreterFlowControl::Break(lv) if lv == &ln => break, _ => return Ok(result), } } } Ok(InterpreterFlowControl::default()) } /// Execute a loop control statement. fn on_loop_control_statemement( &self, is_break: bool, label: &Option<Token>, ) -> InterpreterResult { let name = label.as_ref().map(|token| token.lexeme.clone()); if is_break { Ok(InterpreterFlowControl::Break(name)) } else { Ok(InterpreterFlowControl::Continue(name)) } } /// Execute a return statement. fn on_return_statement( &self, environment: &EnvironmentRef, value: &Option<ast::ExprNode>, ) -> InterpreterResult { let rv = match value { None => Value::Nil, Some(expr) => expr.interpret(environment)?.result(), }; Ok(InterpreterFlowControl::Return(rv)) } } /* -------------------------------- * * INTERPRETER FOR EXPRESSION NODES * * -------------------------------- */ impl Interpretable for ast::ExprNode { fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult { match self { ast::ExprNode::Assignment { name, value } => { let value = value.interpret(environment)?.result(); environment.borrow_mut().assign(name, value)?; Ok(InterpreterFlowControl::default()) } ast::ExprNode::Logical { left, operator, right, } => self.on_logic(environment, left, operator, right), ast::ExprNode::Binary { left, operator, right, } => self.on_binary(environment, left, operator, right), ast::ExprNode::Unary { operator, right } => self.on_unary(environment, operator, right), ast::ExprNode::Grouping { expression } => expression.interpret(environment), ast::ExprNode::Litteral { value } => self.on_litteral(value), ast::ExprNode::Variable { name } => Ok(environment.borrow().get(name)?.into()), ast::ExprNode::Call { callee, right_paren, arguments, } => self.on_call(environment, callee, right_paren, arguments), } } } impl ast::ExprNode { /// Evaluate a logical operator. fn on_logic( &self, environment: &EnvironmentRef, left: &ast::ExprNode, operator: &Token, right: &ast::ExprNode, ) -> InterpreterResult { let left_value = left.interpret(environment)?.result(); if operator.token_type == TokenType::Or && left_value.is_truthy() || operator.token_type == TokenType::And && !left_value.is_truthy() { Ok(left_value.into()) } else { right.interpret(environment) } } /// Evaluate a binary operator. fn on_binary( &self, environment: &EnvironmentRef, left: &ast::ExprNode, operator: &Token, right: &ast::ExprNode, ) -> InterpreterResult { let left_value = left.interpret(environment)?.result(); let right_value = right.interpret(environment)?.result(); match operator.token_type { TokenType::Plus => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a + b).into()), (Value::String(a), Value::String(b)) => Ok(Value::String(a + &b).into()), _ => Err(InterpreterError::new(operator, "type error")), }, TokenType::Minus => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a - b).into()), _ => Err(InterpreterError::new(operator, "type error")), }, TokenType::Star => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a * b).into()), (Value::String(a), Value::Number(b)) => { Ok(Value::String(a.repeat(b as usize)).into()) } _ => Err(InterpreterError::new(operator, "type error")), }, TokenType::Slash => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => { if b == 0. { Err(InterpreterError::new(operator, "division by zero")) } else { Ok(Value::Number(a / b).into()) } } _ => Err(InterpreterError::new(operator, "type error")), }, TokenType::Greater => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a > b).into()), _ => Err(InterpreterError::new(operator, "type error")), }, TokenType::GreaterEqual => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a >= b).into()), _ => Err(InterpreterError::new(operator, "type error")), }, TokenType::Less => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a < b).into()), _ => Err(InterpreterError::new(operator, "type error")), }, TokenType::LessEqual => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a <= b).into()), _ => Err(InterpreterError::new(operator, "type error")), }, TokenType::EqualEqual => Ok(Value::Boolean(left_value == right_value).into()), TokenType::BangEqual => Ok(Value::Boolean(left_value != right_value).into()), _ => panic!( "Unsupported token type for binary operator (token {:?})", operator ), } } /// Evaluate an unary operator. fn on_unary( &self, environment: &EnvironmentRef, operator: &Token, right: &ast::ExprNode, ) -> InterpreterResult { let right_value = right.interpret(environment)?.result(); match operator.token_type { TokenType::Minus => { if let Value::Number(n) = right_value { Ok(Value::Number(-n).into()) } else { Err(InterpreterError::new(operator, "number expected")) } } TokenType::Bang => Ok(Value::Boolean(!right_value.is_truthy()).into()), _ => panic!( "Unsupported token type for unary operator (token {:?})", operator ), } } /// Evaluate a litteral. fn on_litteral(&self, value: &Token) -> InterpreterResult { let out_value = match &value.token_type { TokenType::Nil => Value::Nil, TokenType::True => Value::Boolean(true), TokenType::False => Value::Boolean(false), TokenType::Number(n) => Value::Number(*n), TokenType::String(s) => Value::String(s.clone()), _ => panic!("Unsupported token type for litteral (token {:?})", value), }; Ok(out_value.into()) } /// Evaluate a function call. fn on_call( &self, environment: &EnvironmentRef, callee: &ast::ExprNode, right_paren: &Token, arguments: &Vec<ast::ExprNode>, ) -> InterpreterResult { let callee = callee.interpret(environment)?.result(); let arg_values = { let mut v = Vec::with_capacity(arguments.len()); for argument in arguments.iter() { v.push(argument.interpret(environment)?.result()); } v }; if let Value::Callable(callable_ref) = &callee { let callable = callable_ref.borrow(); if callable.arity() != arg_values.len() { Err(InterpreterError::new( right_paren, &format!( "expected {} arguments, found {}", arg_values.len(), callable.arity() ), )) } else { Ok(callable.call(environment, arg_values)?.into()) } } else { Err(InterpreterError::new( right_paren, "can only call functions and classes", )) } } }