From bf6e150085a41c03b4611893c318a907eced18a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 31 Dec 2022 15:49:31 +0100 Subject: [PATCH] Interpreter - Split into multiple modules --- src/interpreter/interpretable.rs | 181 +++++++++++++++++++++++++++ src/interpreter/mod.rs | 205 +------------------------------ src/interpreter/value.rs | 21 ++++ 3 files changed, 206 insertions(+), 201 deletions(-) create mode 100644 src/interpreter/interpretable.rs create mode 100644 src/interpreter/value.rs diff --git a/src/interpreter/interpretable.rs b/src/interpreter/interpretable.rs new file mode 100644 index 0000000..84ac43f --- /dev/null +++ b/src/interpreter/interpretable.rs @@ -0,0 +1,181 @@ +use crate::{ + ast, + errors::{ErrorHandler, InterpreterError}, + interpreter::Value, + tokens::{Token, TokenType}, +}; + +/// An Interpretable can be evaluated and will return a value. +pub trait Interpretable { + fn interprete(&self) -> Result; +} + +/// Evaluate an interpretable, returning its value. +pub fn evaluate(err_hdl: &mut ErrorHandler, ast: &dyn Interpretable) -> Option { + match ast.interprete() { + Ok(v) => Some(v), + Err(e) => { + e.report(err_hdl); + None + } + } +} + +/* ----------------------------- * + * INTERPRETER FOR PROGRAM NODES * + * ----------------------------- */ + +impl Interpretable for ast::ProgramNode { + fn interprete(&self) -> Result { + for stmt in self.0.iter() { + stmt.interprete()?; + } + Ok(Value::Nil) + } +} + +/* ------------------------------- * + * INTERPRETER FOR STATEMENT NODES * + * ------------------------------- */ + +impl Interpretable for ast::StmtNode { + fn interprete(&self) -> Result { + match self { + ast::StmtNode::Expression(expr) => expr.interprete(), + ast::StmtNode::Print(expr) => { + let value = expr.interprete()?; + 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, + }; + println!("{}", output); + Ok(Value::Nil) + } + } + } +} + +/* -------------------------------- * + * INTERPRETER FOR EXPRESSION NODES * + * -------------------------------- */ + +impl Interpretable for ast::ExprNode { + fn interprete(&self) -> Result { + match self { + ast::ExprNode::Binary { + left, + operator, + right, + } => self.on_binary(left, operator, right), + ast::ExprNode::Unary { operator, right } => self.on_unary(operator, right), + ast::ExprNode::Grouping { expression } => expression.interprete(), + ast::ExprNode::Litteral { value } => self.on_litteral(value), + } + } +} + +impl ast::ExprNode { + /// Evaluate a binary operator. + fn on_binary( + &self, + left: &ast::ExprNode, + operator: &Token, + right: &ast::ExprNode, + ) -> Result { + let left_value = left.interprete()?; + let right_value = right.interprete()?; + match operator.token_type { + TokenType::Plus => match (left_value, right_value) { + (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a + b)), + (Value::String(a), Value::String(b)) => Ok(Value::String(a + &b)), + _ => Err(InterpreterError::new(operator, "type error")), + }, + + TokenType::Minus => match (left_value, right_value) { + (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a - b)), + _ => Err(InterpreterError::new(operator, "type error")), + }, + + TokenType::Star => match (left_value, right_value) { + (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a * b)), + (Value::String(a), Value::Number(b)) => Ok(Value::String(a.repeat(b as usize))), + _ => 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)) + } + } + _ => Err(InterpreterError::new(operator, "type error")), + }, + + TokenType::Greater => match (left_value, right_value) { + (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a > b)), + _ => Err(InterpreterError::new(operator, "type error")), + }, + + TokenType::GreaterEqual => match (left_value, right_value) { + (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a >= b)), + _ => Err(InterpreterError::new(operator, "type error")), + }, + + TokenType::Less => match (left_value, right_value) { + (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a < b)), + _ => Err(InterpreterError::new(operator, "type error")), + }, + + TokenType::LessEqual => match (left_value, right_value) { + (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a <= b)), + _ => Err(InterpreterError::new(operator, "type error")), + }, + + TokenType::Equal => Ok(Value::Boolean(left_value == right_value)), + TokenType::BangEqual => Ok(Value::Boolean(left_value != right_value)), + + _ => panic!( + "Unsupported token type for binary operator (token {:?})", + operator + ), + } + } + + /// Evaluate an unary operator. + fn on_unary(&self, operator: &Token, right: &ast::ExprNode) -> Result { + let right_value = right.interprete()?; + match operator.token_type { + TokenType::Minus => { + if let Value::Number(n) = right_value { + Ok(Value::Number(-n)) + } else { + Err(InterpreterError::new(operator, "number expected")) + } + } + + TokenType::Bang => Ok(Value::Boolean(!right_value.is_truthy())), + + _ => panic!( + "Unsupported token type for unary operator (token {:?})", + operator + ), + } + } + + /// Evaluate a litteral. + fn on_litteral(&self, value: &Token) -> Result { + match &value.token_type { + TokenType::Nil => Ok(Value::Nil), + TokenType::True => Ok(Value::Boolean(true)), + TokenType::False => Ok(Value::Boolean(false)), + TokenType::Number(n) => Ok(Value::Number(*n)), + TokenType::String(s) => Ok(Value::String(s.clone())), + _ => panic!("Unsupported token type for litteral (token {:?})", value), + } + } +} diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 8d470c2..4b189c2 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -1,202 +1,5 @@ -use crate::{ - ast, - errors::{ErrorHandler, InterpreterError}, - tokens::{Token, TokenType}, -}; +mod interpretable; +mod value; -/// A value being handled by the interpreter. -#[derive(Debug, Clone, PartialEq)] -pub enum Value { - Nil, - Boolean(bool), - String(String), - Number(f64), -} - -impl Value { - /// Check whether a value is truthy or not. - pub fn is_truthy(&self) -> bool { - if self == &Value::Nil { - false - } else if let Value::Boolean(b) = self { - *b - } else { - true - } - } -} - -/// An Interpretable can be evaluated and will return a value. -pub trait Interpretable { - fn interprete(&self) -> Result; -} - -/// Evaluate an interpretable, returning its value. -pub fn evaluate(err_hdl: &mut ErrorHandler, ast: &dyn Interpretable) -> Option { - match ast.interprete() { - Ok(v) => Some(v), - Err(e) => { - e.report(err_hdl); - None - } - } -} - -/* ----------------------------- * - * INTERPRETER FOR PROGRAM NODES * - * ----------------------------- */ - -impl Interpretable for ast::ProgramNode { - fn interprete(&self) -> Result { - for stmt in self.0.iter() { - stmt.interprete()?; - } - Ok(Value::Nil) - } -} - -/* ------------------------------- * - * INTERPRETER FOR STATEMENT NODES * - * ------------------------------- */ - -impl Interpretable for ast::StmtNode { - fn interprete(&self) -> Result { - match self { - ast::StmtNode::Expression(expr) => expr.interprete(), - ast::StmtNode::Print(expr) => { - let value = expr.interprete()?; - 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, - }; - println!("{}", output); - Ok(Value::Nil) - } - } - } -} - -/* -------------------------------- * - * INTERPRETER FOR EXPRESSION NODES * - * -------------------------------- */ - -impl Interpretable for ast::ExprNode { - fn interprete(&self) -> Result { - match self { - ast::ExprNode::Binary { - left, - operator, - right, - } => self.on_binary(left, operator, right), - ast::ExprNode::Unary { operator, right } => self.on_unary(operator, right), - ast::ExprNode::Grouping { expression } => expression.interprete(), - ast::ExprNode::Litteral { value } => self.on_litteral(value), - } - } -} - -impl ast::ExprNode { - /// Evaluate a binary operator. - fn on_binary( - &self, - left: &ast::ExprNode, - operator: &Token, - right: &ast::ExprNode, - ) -> Result { - let left_value = left.interprete()?; - let right_value = right.interprete()?; - match operator.token_type { - TokenType::Plus => match (left_value, right_value) { - (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a + b)), - (Value::String(a), Value::String(b)) => Ok(Value::String(a + &b)), - _ => Err(InterpreterError::new(operator, "type error")), - }, - - TokenType::Minus => match (left_value, right_value) { - (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a - b)), - _ => Err(InterpreterError::new(operator, "type error")), - }, - - TokenType::Star => match (left_value, right_value) { - (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a * b)), - (Value::String(a), Value::Number(b)) => Ok(Value::String(a.repeat(b as usize))), - _ => 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)) - } - } - _ => Err(InterpreterError::new(operator, "type error")), - }, - - TokenType::Greater => match (left_value, right_value) { - (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a > b)), - _ => Err(InterpreterError::new(operator, "type error")), - }, - - TokenType::GreaterEqual => match (left_value, right_value) { - (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a >= b)), - _ => Err(InterpreterError::new(operator, "type error")), - }, - - TokenType::Less => match (left_value, right_value) { - (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a < b)), - _ => Err(InterpreterError::new(operator, "type error")), - }, - - TokenType::LessEqual => match (left_value, right_value) { - (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a <= b)), - _ => Err(InterpreterError::new(operator, "type error")), - }, - - TokenType::Equal => Ok(Value::Boolean(left_value == right_value)), - TokenType::BangEqual => Ok(Value::Boolean(left_value != right_value)), - - _ => panic!( - "Unsupported token type for binary operator (token {:?})", - operator - ), - } - } - - /// Evaluate an unary operator. - fn on_unary(&self, operator: &Token, right: &ast::ExprNode) -> Result { - let right_value = right.interprete()?; - match operator.token_type { - TokenType::Minus => { - if let Value::Number(n) = right_value { - Ok(Value::Number(-n)) - } else { - Err(InterpreterError::new(operator, "number expected")) - } - } - - TokenType::Bang => Ok(Value::Boolean(!right_value.is_truthy())), - - _ => panic!( - "Unsupported token type for unary operator (token {:?})", - operator - ), - } - } - - /// Evaluate a litteral. - fn on_litteral(&self, value: &Token) -> Result { - match &value.token_type { - TokenType::Nil => Ok(Value::Nil), - TokenType::True => Ok(Value::Boolean(true)), - TokenType::False => Ok(Value::Boolean(false)), - TokenType::Number(n) => Ok(Value::Number(*n)), - TokenType::String(s) => Ok(Value::String(s.clone())), - _ => panic!("Unsupported token type for litteral (token {:?})", value), - } - } -} +pub use interpretable::*; +pub use value::*; diff --git a/src/interpreter/value.rs b/src/interpreter/value.rs new file mode 100644 index 0000000..82da70b --- /dev/null +++ b/src/interpreter/value.rs @@ -0,0 +1,21 @@ +/// A value being handled by the interpreter. +#[derive(Debug, Clone, PartialEq)] +pub enum Value { + Nil, + Boolean(bool), + String(String), + Number(f64), +} + +impl Value { + /// Check whether a value is truthy or not. + pub fn is_truthy(&self) -> bool { + if self == &Value::Nil { + false + } else if let Value::Boolean(b) = self { + *b + } else { + true + } + } +}