Skip to content

Commit

Permalink
feat: environment + variable assignment/reference
Browse files Browse the repository at this point in the history
  • Loading branch information
ZakFarmer committed Oct 20, 2023
1 parent 60d196a commit f71ea22
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 105 deletions.
259 changes: 157 additions & 102 deletions src/evaluator.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,35 @@

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);
static ref FALSE: Object = Object::Boolean(false);
static ref NULL: Object = Object::Null;
}

pub fn eval(node: Node) -> Result<Object> {
pub fn eval(node: Node, env: &Env) -> Result<Arc<Object>> {
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<Statement>) -> Result<Object> {
let mut result: Object = NULL.clone();
pub fn eval_statements(statements: &Vec<Statement>, env: &Env) -> Result<Arc<Object>> {
let mut result: Arc<Object> = 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,
}
}

Expand All @@ -47,60 +44,68 @@ fn is_truthy(object: &Object) -> bool {
}
}

fn eval_expression(expression: &Expression) -> Result<Object> {
fn eval_expression(expression: &Expression, env: &Env) -> Result<Arc<Object>> {
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<Object> {
fn eval_if_expression(expression: &Expression, env: &Env) -> Result<Arc<Object>> {
if let Expression::If(IfExpression {
condition,
consequence,
alternative,
..
}) = 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 {
Err(Error::msg(format!("Unknown expression type: {}", expression)))
}
}

fn eval_infix_expression(operator: String, left: &Expression, right: &Expression) -> Result<Object> {
let left = eval_expression(left)?;
let right = eval_expression(right)?;

fn eval_infix_expression(operator: String, left: &Object, right: &Object, env: &Env) -> Result<Arc<Object>> {
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: {}",
Expand All @@ -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<Object> {
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<Arc<Object>> {
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<Object> {
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<Arc<Object>> {
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<Object> {
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<Arc<Object>> {
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<Object> {
let right = eval_expression(right)?;
Ok(result.into())
}

fn eval_prefix_expression(operator: String, right: &Object, env: &Env) -> Result<Arc<Object>> {
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<Arc<Object>> {
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<Arc<Object>> {
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<Object> {
fn eval_statement(statement: &Statement, env: &Env) -> Result<Arc<Object>> {
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<Object> {
unimplemented!("eval_identifier");
fn eval_identifier(identifier: String, env: &Env) -> Result<Arc<Object>> {
match env.borrow().get(&identifier) {
Some(value) => Ok(value),
None => Err(Error::msg(format!("Identifier not found: {}", identifier))),
}
}

fn eval_literal(literal: &Literal) -> Result<Object> {
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<Arc<Object>> {
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 {
Expand All @@ -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::*;

Expand Down Expand Up @@ -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<Object, Error> {
#[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<Arc<Object>, 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<Object>, expected: bool) -> Result<(), Error> {
if let Object::Boolean(boolean) = *object {
assert_eq!(boolean, expected);
} else {
return Err(anyhow::anyhow!("Object is not a Boolean."));
Expand All @@ -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<Object>, expected: i64) -> Result<(), Error> {
if let Object::Integer(integer) = *object {
assert_eq!(integer, expected);
} else {
return Err(anyhow::anyhow!("Object is not an Integer."));
Expand Down
Loading

0 comments on commit f71ea22

Please sign in to comment.