use std::{cell::RefCell, rc::Rc}; use crate::{ ast, errors::{ErrorKind, SloxError, SloxResult}, interpreter::{functions::Function, Environment, EnvironmentRef, Value}, resolver::ResolvedVariables, tokens::{Token, TokenType}, }; /// Evaluate an interpretable, returning its value. pub fn evaluate(ast: &ast::ProgramNode, vars: ResolvedVariables) -> SloxResult<Value> { let mut state = InterpreterState::new(&vars); ast.interpret(&mut state).map(|v| v.result()) } /* ------- * * HELPERS * * ------- */ /// The state of the interpreter. #[derive(Debug)] pub struct InterpreterState<'a> { pub(super) globals: EnvironmentRef, pub(super) environment: EnvironmentRef, pub(super) variables: &'a ResolvedVariables, } impl<'a> InterpreterState<'a> { /// Initialize the interpreter state from the resolved variables map. fn new(vars: &'a ResolvedVariables) -> Self { let env = Rc::new(RefCell::new(Environment::default())); Self { environment: env.clone(), globals: env, variables: &vars, } } /// Create a child state. fn create_child<'b>(parent: &InterpreterState<'b>) -> Self where 'b: 'a, { InterpreterState { environment: Environment::create_child(&parent.environment), globals: parent.globals.clone(), variables: parent.variables, } } } /// Interpreter flow control, which may be either a value, a loop break or a /// loop continuation. #[derive(Debug)] pub(super) 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(super) 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. 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(super) type InterpreterResult = SloxResult<InterpreterFlowControl>; /// An Interpretable can be evaluated and will return a value. pub(super) trait Interpretable { fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult; } /// Generate an error with a static message. fn error<T>(token: &Token, message: &str) -> SloxResult<T> { Err(SloxError::with_token( ErrorKind::Runtime, token, message.to_owned(), )) } /* ----------------------------- * * INTERPRETER FOR PROGRAM NODES * * ----------------------------- */ impl Interpretable for ast::ProgramNode { fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult { for stmt in self.0.iter() { stmt.interpret(es)?; } Ok(InterpreterFlowControl::default()) } } /* ------------------------------- * * INTERPRETER FOR STATEMENT NODES * * ------------------------------- */ impl Interpretable for ast::StmtNode { fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult { match self { ast::StmtNode::VarDecl(name, expr) => self.on_var_decl(es, name, expr), ast::StmtNode::FunDecl { name, params, body } => { self.on_fun_decl(es, name, params, body) } ast::StmtNode::Expression(expr) => expr.interpret(es), ast::StmtNode::Print(expr) => self.on_print(es, expr), ast::StmtNode::Block(statements) => self.on_block(es, statements), ast::StmtNode::If { condition, then_branch, else_branch, } => self.on_if_statement(es, condition, then_branch, else_branch), ast::StmtNode::Loop { label, condition, body, after_body, } => self.on_loop_statement(es, 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(es, value), } } } impl ast::StmtNode { /// Handle the `print` statement. fn on_print(&self, es: &mut InterpreterState, expr: &ast::ExprNode) -> InterpreterResult { let value = expr.interpret(es)?.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, es: &mut InterpreterState, name: &Token, initializer: &Option<ast::ExprNode>, ) -> InterpreterResult { let variable = match initializer { Some(expr) => Some(expr.interpret(es)?.result()), None => None, }; es.environment.borrow_mut().define(name, variable)?; Ok(InterpreterFlowControl::default()) } /// Handle a function declaration. fn on_fun_decl( &self, es: &mut InterpreterState, name: &Token, params: &[Token], body: &[ast::StmtNode], ) -> InterpreterResult { let fun = Function::new(Some(name), params, body); es.environment .borrow_mut() .define(name, Some(Value::Callable(fun)))?; Ok(InterpreterFlowControl::default()) } /// Execute the contents of a block. fn on_block(&self, es: &mut InterpreterState, stmts: &[ast::StmtNode]) -> InterpreterResult { let mut child = InterpreterState::create_child(es); for stmt in stmts.iter() { let result = stmt.interpret(&mut child)?; if result.is_flow_control() { return Ok(result); } } Ok(InterpreterFlowControl::default()) } /// Execute an if statement. fn on_if_statement( &self, es: &mut InterpreterState, condition: &ast::ExprNode, then_branch: &ast::StmtNode, else_branch: &Option<Box<ast::StmtNode>>, ) -> InterpreterResult { if condition.interpret(es)?.result().is_truthy() { then_branch.interpret(es) } else if let Some(else_stmt) = else_branch { else_stmt.interpret(es) } else { Ok(InterpreterFlowControl::default()) } } /// Execute a while statement. fn on_loop_statement( &self, es: &mut InterpreterState, 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(es)?.result().is_truthy() { let result = body.interpret(es)?; 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(es)?; 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, es: &mut InterpreterState, value: &Option<ast::ExprNode>, ) -> InterpreterResult { let rv = match value { None => Value::Nil, Some(expr) => expr.interpret(es)?.result(), }; Ok(InterpreterFlowControl::Return(rv)) } } /* -------------------------------- * * INTERPRETER FOR EXPRESSION NODES * * -------------------------------- */ impl Interpretable for ast::ExprNode { fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult { match self { ast::ExprNode::Assignment { name, value } => { let value = value.interpret(es)?.result(); es.environment.borrow_mut().assign(name, value)?; Ok(InterpreterFlowControl::default()) } ast::ExprNode::Logical { left, operator, right, } => self.on_logic(es, left, operator, right), ast::ExprNode::Binary { left, operator, right, } => self.on_binary(es, left, operator, right), ast::ExprNode::Unary { operator, right } => self.on_unary(es, operator, right), ast::ExprNode::Grouping { expression } => expression.interpret(es), ast::ExprNode::Litteral { value } => self.on_litteral(value), ast::ExprNode::Variable { name } => Ok(es.environment.borrow().get(name)?.into()), ast::ExprNode::Call { callee, right_paren, arguments, } => self.on_call(es, callee, right_paren, arguments), ast::ExprNode::Lambda { params, body } => { Ok(Value::Callable(Function::new(None, params, body)).into()) } } } } impl ast::ExprNode { /// Evaluate a logical operator. fn on_logic( &self, es: &mut InterpreterState, left: &ast::ExprNode, operator: &Token, right: &ast::ExprNode, ) -> InterpreterResult { let left_value = left.interpret(es)?.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(es) } } /// Evaluate a binary operator. fn on_binary( &self, es: &mut InterpreterState, left: &ast::ExprNode, operator: &Token, right: &ast::ExprNode, ) -> InterpreterResult { let left_value = left.interpret(es)?.result(); let right_value = right.interpret(es)?.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()), _ => error(operator, "type error"), }, TokenType::Minus => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a - b).into()), _ => error(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()) } _ => error(operator, "type error"), }, TokenType::Slash => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => { if b == 0. { error(operator, "division by zero") } else { Ok(Value::Number(a / b).into()) } } _ => error(operator, "type error"), }, TokenType::Greater => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a > b).into()), _ => error(operator, "type error"), }, TokenType::GreaterEqual => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a >= b).into()), _ => error(operator, "type error"), }, TokenType::Less => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a < b).into()), _ => error(operator, "type error"), }, TokenType::LessEqual => match (left_value, right_value) { (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a <= b).into()), _ => error(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, es: &mut InterpreterState, operator: &Token, right: &ast::ExprNode, ) -> InterpreterResult { let right_value = right.interpret(es)?.result(); match operator.token_type { TokenType::Minus => { if let Value::Number(n) = right_value { Ok(Value::Number(-n).into()) } else { error(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, es: &mut InterpreterState, callee: &ast::ExprNode, right_paren: &Token, arguments: &Vec<ast::ExprNode>, ) -> InterpreterResult { let callee = callee.interpret(es)?.result(); let arg_values = { let mut v = Vec::with_capacity(arguments.len()); for argument in arguments.iter() { v.push(argument.interpret(es)?.result()); } v }; if let Value::Callable(callable_ref) = &callee { let callable = callable_ref.borrow(); if callable.arity() != arg_values.len() { Err(SloxError::with_token( ErrorKind::Runtime, right_paren, format!( "expected {} arguments, found {}", arg_values.len(), callable.arity() ), )) } else { Ok(callable.call(es, arg_values)?.into()) } } else { error(right_paren, "can only call functions and classes") } } }