use crate::parse::ast::{ BinaryOp, DeclareFunction, ExpressionList, Print, Program, UnaryOp, ValueExpression, VoidExpression, }; use crate::runtime::executor::Visitor; use crate::runtime::value::{ForgeValue, UnsupportedOperation}; use std::collections::HashMap; use std::error::Error; use std::fmt::{Debug, Display, Formatter}; #[derive(Clone, Default)] pub struct SimpleExecutor { data: HashMap<String, ForgeValue>, vtable: HashMap<String, DeclareFunction>, } #[derive(Clone, Debug, PartialEq)] pub enum RuntimeError { Unsupported(&'static str), BadOperands(UnsupportedOperation), } impl From<UnsupportedOperation> for RuntimeError { fn from(value: UnsupportedOperation) -> Self { Self::BadOperands(value) } } impl Display for RuntimeError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { RuntimeError::Unsupported(expr) => { write!( f, "[Runtime] Encountered an unsupported expression: {}", expr ) } RuntimeError::BadOperands(unsupported) => write!(f, "[Runtime] {}", unsupported), } } } impl Error for RuntimeError {} impl SimpleExecutor { fn evaluate_expression_list( &mut self, list: &ExpressionList, ) -> Result<ForgeValue, RuntimeError> { let mut last_val = Ok(ForgeValue::Null); for expr in &list.expressions { last_val = Ok(self.evaluate_expression(expr)?); } if list.is_void { Ok(ForgeValue::Null) } else { last_val } } } impl Visitor for SimpleExecutor { type Output = ForgeValue; type Error = RuntimeError; fn evaluate_value_expression( &mut self, expression: &ValueExpression, ) -> Result<Self::Output, Self::Error> { match expression { ValueExpression::Unary { operator, operand } => { let value = self.evaluate_value_expression(operand.as_ref())?; match operator { UnaryOp::Negate => Ok(value.invert()), UnaryOp::Not => Ok(!value), } } ValueExpression::Binary { operator, lhs, rhs } => { let lhs = self.evaluate_value_expression(lhs.as_ref())?; let rhs = self.evaluate_value_expression(rhs.as_ref())?; match operator { BinaryOp::Add => Ok(lhs + rhs), BinaryOp::Subtract => Ok((lhs - rhs)?), BinaryOp::Divide => Ok((lhs / rhs)?), BinaryOp::Multiply => Ok((lhs * rhs)?), BinaryOp::Modulo => Ok((lhs % rhs)?), BinaryOp::Equals => Ok((lhs == rhs).into()), } } ValueExpression::Grouped(group) => self.evaluate_value_expression(group.inner.as_ref()), ValueExpression::Block(_) => Err(RuntimeError::Unsupported("Block")), ValueExpression::Literal(lit) => Ok(ForgeValue::from(lit.clone())), ValueExpression::DeclareIdentifier(_) => { Err(RuntimeError::Unsupported("DeclareIdentifier")) } ValueExpression::Assignment(_) => Err(RuntimeError::Unsupported("Assignment")), ValueExpression::ConditionalBlock(_) => { Err(RuntimeError::Unsupported("ConditionalBlock")) } ValueExpression::Identifier(_) => Err(RuntimeError::Unsupported("Identifier")), ValueExpression::FunctionCall(_) => Err(RuntimeError::Unsupported("FunctionCall")), ValueExpression::DeclareFunction(_) => { Err(RuntimeError::Unsupported("DeclareFunction")) } } } fn evaluate_void_expression( &mut self, expression: &VoidExpression, ) -> Result<Self::Output, Self::Error> { match expression { VoidExpression::ConditionLoop(_) => { return Err(RuntimeError::Unsupported("ConditionLoop")) } VoidExpression::Import(_) => return Err(RuntimeError::Unsupported("Import")), VoidExpression::Export(_) => return Err(RuntimeError::Unsupported("Export")), VoidExpression::Print(Print { expr }) => { let value = self.evaluate_value_expression(expr.as_ref())?; println!("{}", value); } } Ok(ForgeValue::Null) } fn evaluate_program(&mut self, program: &Program) -> Result<Self::Output, Self::Error> { self.evaluate_expression_list(&program.0) } } #[cfg(test)] mod interpreter_test { use crate::parse::parse_program; use crate::runtime::executor::simple::{RuntimeError, SimpleExecutor}; use crate::runtime::executor::Visitor; use crate::runtime::value::ForgeValue; #[test] fn the_basics() { let add_numbers = parse_program("1 + 1").expect("Failed to parse"); let add_strings = parse_program("\"foo\" + \" \" + \"bar\"").expect("Failed to parse"); let concat_string_num = parse_program("\"#\" + 1").expect("Failed to parse"); let bad_mult = parse_program("false * 123").expect("Failed to parse"); let mut vm = SimpleExecutor::default(); assert_eq!(vm.evaluate_program(&add_numbers), Ok(ForgeValue::from(2))); assert_eq!( vm.evaluate_program(&add_strings), Ok(ForgeValue::from("foo bar")) ); assert_eq!( vm.evaluate_program(&concat_string_num), Ok(ForgeValue::from("#1")) ); assert!(matches!( vm.evaluate_program(&bad_mult), Err(RuntimeError::BadOperands(_)) )) } #[test] fn combos() { let add_numbers = parse_program("1 + -1").expect("Failed to parse"); let mut vm = SimpleExecutor::default(); assert_eq!(vm.evaluate_program(&add_numbers), Ok(ForgeValue::from(0))); } #[test] fn print() { let print_4 = parse_program("print 2 + 2").expect("Failed to parse"); let mut vm = SimpleExecutor::default(); assert_eq!(vm.evaluate_program(&print_4), Ok(ForgeValue::Null)); } }