diff --git a/src/evaluator.rs b/src/evaluator.rs index 456a2c7..2caecda 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -1,8 +1,10 @@ +use std::sync::Arc; + use anyhow::{Result, Ok, Error}; use lazy_static::lazy_static; -use crate::{ast::{Boolean, Expression, Literal, Node, Statement, IfExpression}, object::Object}; +use crate::{ast::{Boolean, Expression, Literal, Node, Statement, IfExpression}, object::{Object, environment::Env}}; lazy_static! { static ref TRUE: Object = Object::Boolean(true); @@ -10,29 +12,24 @@ lazy_static! { static ref NULL: Object = Object::Null; } -pub fn eval(node: Node) -> Result { +pub fn eval(node: Node, env: &Env) -> Result> { match node { - Node::Expression(expression) => eval_expression(&expression), - Node::Program(program) => eval_statements(&program.statements), - Node::Statement(statement) => eval_statement(&statement), + Node::Expression(expression) => eval_expression(&expression, env), + Node::Program(program) => eval_statements(&program.statements, env), + Node::Statement(statement) => eval_statement(&statement, env), _ => Err(Error::msg(format!("Unknown node type: {}", node))), } } -pub fn eval_statements(statements: &Vec) -> Result { - let mut result: Object = NULL.clone(); +pub fn eval_statements(statements: &Vec, env: &Env) -> Result> { + let mut result: Arc = Arc::new(Object::Null); for statement in statements { - let val = eval_statement(statement); - - if let Err(err) = val { - return Err(err); - } + let val = eval_statement(statement, env)?; - result = val.unwrap(); - - if let Object::Return(value) = result { - return Ok(*value); + match *val { + Object::Return(_) => return Ok(val), + _ => result = val, } } @@ -47,25 +44,36 @@ fn is_truthy(object: &Object) -> bool { } } -fn eval_expression(expression: &Expression) -> Result { +fn eval_expression(expression: &Expression, env: &Env) -> Result> { match expression { - Expression::Identifier(identifier_expression) => eval_identifier(identifier_expression.to_string()), + Expression::Identifier(identifier_expression) => eval_identifier(identifier_expression.to_string(), env), Expression::Literal(literal) => eval_literal(&literal), - Expression::Infix(infix_expression) => eval_infix_expression( - infix_expression.operator.to_string(), - &infix_expression.left, - &infix_expression.right, - ), - Expression::Prefix(prefix_expression) => eval_prefix_expression( - prefix_expression.operator.to_string(), - &prefix_expression.right - ), - Expression::If(if_expression) => eval_if_expression(expression), + Expression::Infix(infix_expression) => { + let left = eval_expression(&infix_expression.left, &Arc::clone(env))?; + let right = eval_expression(&infix_expression.right, &Arc::clone(env))?; + + eval_infix_expression( + infix_expression.operator.to_string(), + &left, + &right, + env + ) + }, + Expression::Prefix(prefix_expression) => { + let right = eval_expression(&prefix_expression.right, &Arc::clone(env))?; + + eval_prefix_expression( + prefix_expression.operator.to_string(), + &right, + env + ) + }, + Expression::If(if_expression) => eval_if_expression(expression, env), _ => Err(Error::msg(format!("Unknown expression type: {}", expression))), } } -fn eval_if_expression(expression: &Expression) -> Result { +fn eval_if_expression(expression: &Expression, env: &Env) -> Result> { if let Expression::If(IfExpression { condition, consequence, @@ -73,14 +81,14 @@ fn eval_if_expression(expression: &Expression) -> Result { .. }) = expression { - let condition = eval_expression(condition)?; + let condition = eval_expression(condition, env)?; if is_truthy(&condition) { - eval_statements(&consequence.statements) + eval_statements(&consequence.statements, env) } else { match alternative { - Some(alternative) => eval_statements(&alternative.statements), - None => Ok(NULL.clone()), + Some(alternative) => eval_statements(&alternative.statements, env), + None => Ok(Object::Null.into()), } } } else { @@ -88,19 +96,16 @@ fn eval_if_expression(expression: &Expression) -> Result { } } -fn eval_infix_expression(operator: String, left: &Expression, right: &Expression) -> Result { - let left = eval_expression(left)?; - let right = eval_expression(right)?; - +fn eval_infix_expression(operator: String, left: &Object, right: &Object, env: &Env) -> Result> { match (left, right) { (Object::Integer(left), Object::Integer(right)) => { - eval_integer_infix_expression(operator, left, right) + eval_integer_infix_expression(operator, *left, *right) } (Object::Boolean(left), Object::Boolean(right)) => { - eval_boolean_infix_expression(operator, left, right) + eval_boolean_infix_expression(operator, *left, *right) } (Object::String(left), Object::String(right)) => { - eval_string_infix_expression(operator, left, right) + eval_string_infix_expression(operator, left.to_string(), right.to_string()) } _ => Err(Error::msg(format!( "Unknown operator: {}", @@ -109,91 +114,119 @@ fn eval_infix_expression(operator: String, left: &Expression, right: &Expression } } -fn eval_boolean_infix_expression(operator: String, left: bool, right: bool) -> Result { - match operator.as_str() { - "==" => Ok(native_bool_to_bool_object(left == right)), - "!=" => Ok(native_bool_to_bool_object(left != right)), - _ => Err(Error::msg(format!( +fn eval_boolean_infix_expression(operator: String, left: bool, right: bool) -> Result> { + let result = match operator.as_str() { + "==" => native_bool_to_bool_object(left == right), + "!=" => native_bool_to_bool_object(left != right), + _ => return Err(Error::msg(format!( "Unknown operator: {} {} {}", left, operator, right ))), - } + }; + + Ok(result.into()) } -fn eval_integer_infix_expression(operator: String, left: i64, right: i64) -> Result { - match operator.as_str() { - "+" => Ok(Object::Integer(left + right)), - "-" => Ok(Object::Integer(left - right)), - "*" => Ok(Object::Integer(left * right)), - "/" => Ok(Object::Integer(left / right)), - "<" => Ok(native_bool_to_bool_object(left < right)), - ">" => Ok(native_bool_to_bool_object(left > right)), - "==" => Ok(native_bool_to_bool_object(left == right)), - "!=" => Ok(native_bool_to_bool_object(left != right)), - _ => Err(Error::msg(format!( +fn eval_integer_infix_expression(operator: String, left: i64, right: i64) -> Result> { + let result = match operator.as_str() { + "+" => Object::Integer(left + right), + "-" => Object::Integer(left - right), + "*" => Object::Integer(left * right), + "/" => Object::Integer(left / right), + "<" => native_bool_to_bool_object(left < right), + ">" => native_bool_to_bool_object(left > right), + "==" => native_bool_to_bool_object(left == right), + "!=" => native_bool_to_bool_object(left != right), + _ => return Err(Error::msg(format!( "Unknown operator: {} {} {}", left, operator, right ))), - } + }; + + Ok(result.into()) } -fn eval_string_infix_expression(operator: String, left: String, right: String) -> Result { - match operator.as_str() { - "+" => Ok(Object::String(format!("{}{}", left, right))), - _ => Err(Error::msg(format!( +fn eval_string_infix_expression(operator: String, left: String, right: String) -> Result> { + let result = match operator.as_str() { + "+" => Object::String(format!("{}{}", left, right)), + _ => return Err(Error::msg(format!( "Unknown operator: {} {} {}", left, operator, right ))), - } -} + }; -fn eval_prefix_expression(operator: String, right: &Expression) -> Result { - let right = eval_expression(right)?; + Ok(result.into()) +} +fn eval_prefix_expression(operator: String, right: &Object, env: &Env) -> Result> { match operator.as_str() { - "-" => Ok(eval_minus_prefix_operator_expression(right)), - "!" => Ok(eval_bang_operator_expression(right)), - _ => Err(Error::msg(format!( + "-" => eval_minus_prefix_operator_expression(right), + "!" => eval_bang_operator_expression(right), + _ => return Err(Error::msg(format!( "Unknown operator: {}{}", operator, right ))), } } -fn eval_bang_operator_expression(right: Object) -> Object { - match right { - val if val == *TRUE => FALSE.clone(), - val if val == *FALSE => TRUE.clone(), - val if val == *NULL => TRUE.clone(), - _ => FALSE.clone(), - } +fn eval_bang_operator_expression(right: &Object) -> Result> { + let result = match *right { + Object::Null => Arc::new(Object::Boolean(true)), + Object::Boolean(boolean) => Arc::new(Object::Boolean(!boolean)), + _ => Arc::new(Object::Boolean(false)), + }; + + Ok(result.into()) } -fn eval_minus_prefix_operator_expression(right: Object) -> Object { - match right { - Object::Integer(integer) => Object::Integer(-integer), - _ => NULL.clone(), - } +fn eval_minus_prefix_operator_expression(right: &Object) -> Result> { + let result = match *right { + Object::Integer(integer) => Arc::from(Object::Integer(-integer)), + _ => return Err(Error::msg(format!( + "Invalid use of minus operator: -{}", + right + ))), + }; + + Ok(result.into()) } -fn eval_statement(statement: &Statement) -> Result { +fn eval_statement(statement: &Statement, env: &Env) -> Result> { match statement { - Statement::Expr(expression) => eval_expression(expression), + Statement::Expr(expression) => eval_expression(expression, env), + Statement::Assign(assignment) => { + let value = eval_expression(&assignment.value, env)?; + let object = Arc::clone(&value); + + env.borrow_mut().set(assignment.name.to_string(), object); + + Ok(value) + }, + Statement::Return(return_statement) => { + let value = eval_expression(&return_statement.return_value, env)?; + + Ok(Arc::new(Object::Return(value))) + }, _ => Err(Error::msg(format!("Unknown statement type: {}", statement))), } } -fn eval_identifier(_identifier: String) -> Result { - unimplemented!("eval_identifier"); +fn eval_identifier(identifier: String, env: &Env) -> Result> { + match env.borrow().get(&identifier) { + Some(value) => Ok(value), + None => Err(Error::msg(format!("Identifier not found: {}", identifier))), + } } -fn eval_literal(literal: &Literal) -> Result { - match literal { - Literal::Integer(integer) => Ok(Object::Integer(integer.value)), - Literal::Boolean(Boolean { value, .. }) => Ok(Object::Boolean(*value)), - Literal::String(string) => Ok(Object::String(string.value.clone())), - _ => Err(Error::msg(format!("Unknown literal type: {}", literal))), - } +fn eval_literal(literal: &Literal) -> Result> { + let result = match literal { + Literal::Integer(integer) => Object::Integer(integer.value), + Literal::Boolean(Boolean { value, .. }) => Object::Boolean(*value), + Literal::String(string) => Object::String(string.value.clone()), + _ => return Err(Error::msg(format!("Unknown literal type: {}", literal))), + }; + + Ok(result.into()) } fn native_bool_to_bool_object(input: bool) -> Object { @@ -206,9 +239,11 @@ fn native_bool_to_bool_object(input: bool) -> Object { #[cfg(test)] mod tests { + use std::cell::RefCell; + use anyhow::Error; - use crate::{lexer::Lexer, object::Object, parser::Parser}; + use crate::{lexer::Lexer, object::{Object, environment::Environment}, parser::Parser}; use super::*; @@ -314,28 +349,48 @@ mod tests { if let Some(expected) = expected { assert_integer_object(evaluated, expected)?; } else { - assert_eq!(evaluated, *NULL); + assert_eq!(*evaluated, *NULL); } } Ok(()) } - fn assert_eval(input: &str) -> Result { + #[test] + fn test_eval_assertions() -> Result<(), Error> { + let tests = vec![ + ("$a = 5; $a;", 5), + ("$a = 5 * 5; $a;", 25), + ("$a = 5; $a;", 5), + ]; + + for (input, expected) in tests { + let evaluated = assert_eval(input)?; + + dbg!(&evaluated); + + assert_integer_object(evaluated, expected)?; + } + + Ok(()) + } + + fn assert_eval(input: &str) -> Result, Error> { + let env = Arc::new(RefCell::new(Environment::new())); + let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); let program = parser.parse_program(); parser.check_errors()?; - let evaluated = eval_statements(&program.statements) - .or_else(|_| Err(anyhow::anyhow!("eval returned None")))?; + let evaluated = eval(Node::Program(program), &env); - Ok(evaluated) + evaluated } - fn assert_boolean_literal_object(object: Object, expected: bool) -> Result<(), Error> { - if let Object::Boolean(boolean) = object { + fn assert_boolean_literal_object(object: Arc, expected: bool) -> Result<(), Error> { + if let Object::Boolean(boolean) = *object { assert_eq!(boolean, expected); } else { return Err(anyhow::anyhow!("Object is not a Boolean.")); @@ -344,8 +399,8 @@ mod tests { Ok(()) } - fn assert_integer_object(object: Object, expected: i64) -> Result<(), Error> { - if let Object::Integer(integer) = object { + fn assert_integer_object(object: Arc, expected: i64) -> Result<(), Error> { + if let Object::Integer(integer) = *object { assert_eq!(integer, expected); } else { return Err(anyhow::anyhow!("Object is not an Integer.")); diff --git a/src/object/environment.rs b/src/object/environment.rs new file mode 100644 index 0000000..c12b0c2 --- /dev/null +++ b/src/object/environment.rs @@ -0,0 +1,28 @@ +use std::{collections::HashMap, sync::Arc, cell::RefCell}; + +use super::Object; + +pub type Env = Arc>; + +pub struct Environment { + store: HashMap>, +} + +impl Environment { + pub fn new() -> Self { + Self { + store: HashMap::new(), + } + } + + pub fn get(&self, name: &str) -> Option> { + match self.store.get(name) { + Some(value) => Some(Arc::clone(value)), + None => None, + } + } + + pub fn set(&mut self, name: String, value: Arc) -> Option> { + self.store.insert(name, value) + } +} \ No newline at end of file diff --git a/src/object.rs b/src/object/mod.rs similarity index 94% rename from src/object.rs rename to src/object/mod.rs index d839397..7243b05 100644 --- a/src/object.rs +++ b/src/object/mod.rs @@ -1,12 +1,16 @@ +use std::sync::Arc; + use crate::ast::BlockStatement; +pub mod environment; + #[derive(Clone, Debug, PartialEq)] pub enum Object { Integer(i64), Boolean(bool), String(String), Function(Vec, BlockStatement), - Return(Box), + Return(Arc), Null, } diff --git a/src/parser.rs b/src/parser.rs index 42d54f7..bdd2ebd 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -331,6 +331,14 @@ impl<'a> Parser<'a> { None } } + Some(token) if token.token_type == TokenType::Semicolon => { + let identifier = Identifier { + token: name_token.clone(), + value: name_token.literal.clone(), + }; + + Some(Statement::Expr(Expression::Identifier(identifier))) + } Some(token) => { self.errors .push(format!("Expected = or ;, got {:?}", token)); diff --git a/src/repl.rs b/src/repl.rs index c5e9b3f..fec6f53 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -1,8 +1,10 @@ +use std::{sync::Arc, cell::RefCell}; + use anyhow::{Error, Result}; use rustyline::error::ReadlineError; -use crate::{evaluator, lexer::Lexer, parser::Parser}; +use crate::{evaluator, lexer::Lexer, parser::Parser, object::environment::Environment}; const PROMPT: &str = ">> "; @@ -20,6 +22,8 @@ pub fn init_repl() -> Result<(), Error> { env!("CARGO_PKG_VERSION") ); + let env = Arc::new(RefCell::new(Environment::new())); + loop { let readline = rl.readline(format!("{}", PROMPT).as_str()); @@ -33,7 +37,7 @@ pub fn init_repl() -> Result<(), Error> { let program = parser.parse_program(); parser.check_errors()?; - let evaluation = evaluator::eval_statements(&program.statements); + let evaluation = evaluator::eval_statements(&program.statements, &env); if let Ok(evaluated) = evaluation { println!("{}", evaluated);