Skip to content

Commit

Permalink
♻️ refactor evaluator to remove exclusive reference
Browse files Browse the repository at this point in the history
  • Loading branch information
KPMGE committed Apr 27, 2024
1 parent 78fe596 commit 180ed17
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 21 deletions.
36 changes: 23 additions & 13 deletions src/evaluator.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::ast::{AstNode, BlockStatement, Expression, Statement};
use crate::token::Token;
use std::cell::RefCell;
use std::collections::HashMap;

use crate::builtin::{BuiltinFn, BUILTIN_FUNCTIONS};

#[derive(Default)]
pub struct Evaluator {
context: HashMap<String, Object>,
context: RefCell<HashMap<String, Object>>,
}

#[derive(Debug, Clone, PartialEq)]
Expand All @@ -28,19 +29,19 @@ pub enum Object {
impl Evaluator {
pub fn new() -> Self {
Evaluator {
context: HashMap::new(),
context: RefCell::new(HashMap::new()),
}
}

pub fn eval(&mut self, node: AstNode) -> Object {
pub fn eval(&self, node: AstNode) -> Object {
match node {
AstNode::Program { statements } => self.eval_program(statements),
AstNode::Statement(statement) => self.eval_statement(*statement),
AstNode::Expression(expression) => self.eval_expression(*expression),
}
}

fn eval_expression(&mut self, expression: Expression) -> Object {
fn eval_expression(&self, expression: Expression) -> Object {
match expression {
Expression::Array(elems) => {
let elements = self.eval_expressions(elems);
Expand Down Expand Up @@ -111,19 +112,20 @@ impl Evaluator {
}
}

fn eval_identifier(&mut self, name: String) -> Object {
fn eval_identifier(&self, name: String) -> Object {
if let Some(function) = BUILTIN_FUNCTIONS.get(name.as_str()) {
return Object::Builtin(*function);
}

self.context
.borrow()
.get(&name)
.expect("ERROR: Could not find identifer")
.clone()
}

fn eval_function_call(
&mut self,
&self,
parameters: Vec<Token>,
arguments: Vec<Expression>,
body: BlockStatement,
Expand All @@ -143,14 +145,22 @@ impl Evaluator {
_ => panic!(),
});

self.context = scope.clone();
self.context.borrow_mut().clear();
scope.iter().for_each(|(key, value)| {
self.context.borrow_mut().insert(key.clone(), value.clone());
});

let result = self.eval_block_statement(body.statements);
self.context = previous_context;

self.context.borrow_mut().clear();
previous_context.borrow().iter().for_each(|(key, value)| {
self.context.borrow_mut().insert(key.clone(), value.clone());
});

result
}

fn eval_statement(&mut self, statement: Statement) -> Object {
fn eval_statement(&self, statement: Statement) -> Object {
match statement {
Statement::ReturnStatement(value) => {
let result_object = self.eval(AstNode::Expression(value));
Expand All @@ -163,20 +173,20 @@ impl Evaluator {
};

let result_object = self.eval(AstNode::Expression(value));
self.context.insert(let_name.clone(), result_object.clone());
self.context.borrow_mut().insert(let_name, result_object.clone());
result_object
}
}
}

fn eval_expressions(&mut self, expressions: Vec<Expression>) -> Vec<Object> {
fn eval_expressions(&self, expressions: Vec<Expression>) -> Vec<Object> {
expressions
.iter()
.map(|expression| self.eval(AstNode::Expression(Box::new(expression.clone()))))
.collect()
}

fn eval_program(&mut self, statements: Vec<AstNode>) -> Object {
fn eval_program(&self, statements: Vec<AstNode>) -> Object {
let mut result = Object::Null;

for statement in statements {
Expand All @@ -189,7 +199,7 @@ impl Evaluator {
result
}

fn eval_block_statement(&mut self, statements: Vec<AstNode>) -> Object {
fn eval_block_statement(&self, statements: Vec<AstNode>) -> Object {
let mut result = Object::Null;

for statement in statements {
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn main() {
gflags::print_help_and_exit(0);
}

let mut evaluator = Evaluator::new();
let evaluator = Evaluator::new();

loop {
let mut input = String::new();
Expand Down
14 changes: 7 additions & 7 deletions tests/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn given_an_integer_expression_it_should_evaluate_to_the_right_object() {
_ => panic!("Unexpected AstNode!"),
};

let mut evaluator = Evaluator::new();
let evaluator = Evaluator::new();
let evaluated_obj = evaluator.eval(node);

assert_eq!(evaluated_obj, *expected_objects.get(idx).unwrap());
Expand All @@ -36,7 +36,7 @@ fn given_boolean_expressions_it_should_evaluate_to_the_right_object() {
_ => panic!("Unexpected AstNode!"),
};

let mut evaluator = Evaluator::new();
let evaluator = Evaluator::new();
let evaluated_obj = evaluator.eval(node);

assert_eq!(evaluated_obj, *expected_objects.get(idx).unwrap());
Expand All @@ -63,7 +63,7 @@ fn given_prefix_expressions_it_should_evaluate_correctly() {
_ => panic!("Unexpected AstNode!"),
};

let mut evaluator = Evaluator::new();
let evaluator = Evaluator::new();
let evaluated_obj = evaluator.eval(node);

assert_eq!(evaluated_obj, *expected_objects.get(idx).unwrap());
Expand Down Expand Up @@ -98,7 +98,7 @@ fn given_if_else_expressions_it_should_evaluate_correctly() {
_ => panic!("Unexpected AstNode!"),
};

let mut evaluator = Evaluator::new();
let evaluator = Evaluator::new();
let evaluated_obj = evaluator.eval(node);

assert_eq!(evaluated_obj, *expected_objects.get(idx).unwrap());
Expand All @@ -125,7 +125,7 @@ fn given_return_statements_it_should_evaluate_correctly() {
_ => panic!("Unexpected AstNode!"),
};

let mut evaluator = Evaluator::new();
let evaluator = Evaluator::new();
let evaluated_obj = evaluator.eval(node);

assert_eq!(evaluated_obj, *expected_objects.get(idx).unwrap());
Expand All @@ -145,7 +145,7 @@ fn given_a_string_expression_it_should_evaluate_correctly() {
_ => panic!("Unexpected AstNode!"),
};

let mut evaluator = Evaluator::new();
let evaluator = Evaluator::new();
let evaluated_obj = evaluator.eval(node);

assert_eq!(evaluated_obj, expected_obj);
Expand All @@ -164,7 +164,7 @@ fn given_a_string_expression_when_calling_len_it_should_evaluate_correctly() {
_ => panic!("Unexpected AstNode!"),
};

let mut evaluator = Evaluator::new();
let evaluator = Evaluator::new();
let evaluated_obj = evaluator.eval(node);

assert_eq!(evaluated_obj, expected_obj);
Expand Down

0 comments on commit 180ed17

Please sign in to comment.