Skip to content

Commit

Permalink
refactor: simplified $ identifier parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
ZakFarmer committed Oct 22, 2023
1 parent f71ea22 commit 57f178f
Show file tree
Hide file tree
Showing 7 changed files with 376 additions and 359 deletions.
138 changes: 95 additions & 43 deletions src/evaluator.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@

use std::sync::Arc;
use std::{rc::Rc, cell::RefCell};

use anyhow::{Result, Ok, Error};
use lazy_static::lazy_static;

use crate::{ast::{Boolean, Expression, Literal, Node, Statement, IfExpression}, object::{Object, environment::Env}};
use crate::{ast::{Boolean, Expression, Literal, Node, Statement, IfExpression, FunctionLiteral, CallExpression}, object::{Object, environment::{Env, Environment}}};

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, env: &Env) -> Result<Arc<Object>> {
pub fn eval(node: Node, env: &Env) -> Result<Rc<Object>> {
match node {
Node::Expression(expression) => eval_expression(&expression, env),
Node::Program(program) => eval_statements(&program.statements, env),
Expand All @@ -21,8 +15,8 @@ pub fn eval(node: Node, env: &Env) -> Result<Arc<Object>> {
}
}

pub fn eval_statements(statements: &Vec<Statement>, env: &Env) -> Result<Arc<Object>> {
let mut result: Arc<Object> = Arc::new(Object::Null);
pub fn eval_statements(statements: &Vec<Statement>, env: &Env) -> Result<Rc<Object>> {
let mut result: Rc<Object> = Rc::new(Object::Null);

for statement in statements {
let val = eval_statement(statement, env)?;
Expand All @@ -36,6 +30,22 @@ pub fn eval_statements(statements: &Vec<Statement>, env: &Env) -> Result<Arc<Obj
Ok(result)
}

fn apply_function(function: &Rc<Object>, args: &Vec<Rc<Object>>) -> Result<Rc<Object>> {
match &**function {
Object::Function(params, body, env) => {
let mut env = Environment::new_enclosed_environment(&env);

params.iter().enumerate().for_each(|(i, param)| {
env.set(param.value.clone(), args[i].clone());
});

let evaluated = eval_statements(&body.statements, &Rc::new(RefCell::new(env)))?;
return unwrap_return_value(evaluated);
}
f => Err(Error::msg(format!("expected {} to be a function", f))),
}
}

fn is_truthy(object: &Object) -> bool {
match object {
Object::Null => false,
Expand All @@ -44,13 +54,20 @@ fn is_truthy(object: &Object) -> bool {
}
}

fn eval_expression(expression: &Expression, env: &Env) -> Result<Arc<Object>> {
fn unwrap_return_value(object: Rc<Object>) -> Result<Rc<Object>> {
match &* object {
Object::Return(value) => Ok(Rc::clone(value)),
_ => Ok(object),
}
}

fn eval_expression(expression: &Expression, env: &Env) -> Result<Rc<Object>> {
match expression {
Expression::Identifier(identifier_expression) => eval_identifier(identifier_expression.to_string(), env),
Expression::Literal(literal) => eval_literal(&literal),
Expression::Infix(infix_expression) => {
let left = eval_expression(&infix_expression.left, &Arc::clone(env))?;
let right = eval_expression(&infix_expression.right, &Arc::clone(env))?;
let left = eval_expression(&infix_expression.left, &Rc::clone(env))?;
let right = eval_expression(&infix_expression.right, &Rc::clone(env))?;

eval_infix_expression(
infix_expression.operator.to_string(),
Expand All @@ -60,7 +77,7 @@ fn eval_expression(expression: &Expression, env: &Env) -> Result<Arc<Object>> {
)
},
Expression::Prefix(prefix_expression) => {
let right = eval_expression(&prefix_expression.right, &Arc::clone(env))?;
let right = eval_expression(&prefix_expression.right, &Rc::clone(env))?;

eval_prefix_expression(
prefix_expression.operator.to_string(),
Expand All @@ -69,11 +86,34 @@ fn eval_expression(expression: &Expression, env: &Env) -> Result<Arc<Object>> {
)
},
Expression::If(if_expression) => eval_if_expression(expression, env),
Expression::Call(CallExpression { function, token, arguments }) => {
let function = eval_expression(function, env)?; // This should give you a Function object.
let arguments = eval_expressions(arguments, env)?;

apply_function(&function, &arguments)
},
Expression::Function(FunctionLiteral {
parameters,
body,
..
}) => {
Ok(Object::Function(parameters.clone(), body.clone(), Rc::clone(env)).into())
},
_ => Err(Error::msg(format!("Unknown expression type: {}", expression))),
}
}

fn eval_if_expression(expression: &Expression, env: &Env) -> Result<Arc<Object>> {
fn eval_expressions(exprs: &Vec<Expression>, env: &Env) -> Result<Vec<Rc<Object>>> {
let mut list = Vec::new();
for expr in exprs {
let val = eval_expression(expr, &Rc::clone(env))?;
list.push(val);
}

Ok(list)
}

fn eval_if_expression(expression: &Expression, env: &Env) -> Result<Rc<Object>> {
if let Expression::If(IfExpression {
condition,
consequence,
Expand All @@ -96,7 +136,7 @@ fn eval_if_expression(expression: &Expression, env: &Env) -> Result<Arc<Object>>
}
}

fn eval_infix_expression(operator: String, left: &Object, right: &Object, env: &Env) -> Result<Arc<Object>> {
fn eval_infix_expression(operator: String, left: &Object, right: &Object, env: &Env) -> Result<Rc<Object>> {
match (left, right) {
(Object::Integer(left), Object::Integer(right)) => {
eval_integer_infix_expression(operator, *left, *right)
Expand All @@ -114,7 +154,7 @@ fn eval_infix_expression(operator: String, left: &Object, right: &Object, env: &
}
}

fn eval_boolean_infix_expression(operator: String, left: bool, right: bool) -> Result<Arc<Object>> {
fn eval_boolean_infix_expression(operator: String, left: bool, right: bool) -> Result<Rc<Object>> {
let result = match operator.as_str() {
"==" => native_bool_to_bool_object(left == right),
"!=" => native_bool_to_bool_object(left != right),
Expand All @@ -127,7 +167,7 @@ fn eval_boolean_infix_expression(operator: String, left: bool, right: bool) -> R
Ok(result.into())
}

fn eval_integer_infix_expression(operator: String, left: i64, right: i64) -> Result<Arc<Object>> {
fn eval_integer_infix_expression(operator: String, left: i64, right: i64) -> Result<Rc<Object>> {
let result = match operator.as_str() {
"+" => Object::Integer(left + right),
"-" => Object::Integer(left - right),
Expand All @@ -146,7 +186,7 @@ fn eval_integer_infix_expression(operator: String, left: i64, right: i64) -> Res
Ok(result.into())
}

fn eval_string_infix_expression(operator: String, left: String, right: String) -> Result<Arc<Object>> {
fn eval_string_infix_expression(operator: String, left: String, right: String) -> Result<Rc<Object>> {
let result = match operator.as_str() {
"+" => Object::String(format!("{}{}", left, right)),
_ => return Err(Error::msg(format!(
Expand All @@ -158,7 +198,7 @@ fn eval_string_infix_expression(operator: String, left: String, right: String) -
Ok(result.into())
}

fn eval_prefix_expression(operator: String, right: &Object, env: &Env) -> Result<Arc<Object>> {
fn eval_prefix_expression(operator: String, right: &Object, env: &Env) -> Result<Rc<Object>> {
match operator.as_str() {
"-" => eval_minus_prefix_operator_expression(right),
"!" => eval_bang_operator_expression(right),
Expand All @@ -169,19 +209,19 @@ fn eval_prefix_expression(operator: String, right: &Object, env: &Env) -> Result
}
}

fn eval_bang_operator_expression(right: &Object) -> Result<Arc<Object>> {
fn eval_bang_operator_expression(right: &Object) -> Result<Rc<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)),
Object::Null => Rc::new(Object::Boolean(true)),
Object::Boolean(boolean) => Rc::new(Object::Boolean(!boolean)),
_ => Rc::new(Object::Boolean(false)),
};

Ok(result.into())
}

fn eval_minus_prefix_operator_expression(right: &Object) -> Result<Arc<Object>> {
fn eval_minus_prefix_operator_expression(right: &Object) -> Result<Rc<Object>> {
let result = match *right {
Object::Integer(integer) => Arc::from(Object::Integer(-integer)),
Object::Integer(integer) => Rc::from(Object::Integer(-integer)),
_ => return Err(Error::msg(format!(
"Invalid use of minus operator: -{}",
right
Expand All @@ -191,12 +231,12 @@ fn eval_minus_prefix_operator_expression(right: &Object) -> Result<Arc<Object>>
Ok(result.into())
}

fn eval_statement(statement: &Statement, env: &Env) -> Result<Arc<Object>> {
fn eval_statement(statement: &Statement, env: &Env) -> Result<Rc<Object>> {
match statement {
Statement::Expr(expression) => eval_expression(expression, env),
Statement::Assign(assignment) => {
let value = eval_expression(&assignment.value, env)?;
let object = Arc::clone(&value);
let object = Rc::clone(&value);

env.borrow_mut().set(assignment.name.to_string(), object);

Expand All @@ -205,20 +245,20 @@ fn eval_statement(statement: &Statement, env: &Env) -> Result<Arc<Object>> {
Statement::Return(return_statement) => {
let value = eval_expression(&return_statement.return_value, env)?;

Ok(Arc::new(Object::Return(value)))
Ok(Rc::new(Object::Return(value)))
},
_ => Err(Error::msg(format!("Unknown statement type: {}", statement))),
}
}

fn eval_identifier(identifier: String, env: &Env) -> Result<Arc<Object>> {
fn eval_identifier(identifier: String, env: &Env) -> Result<Rc<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<Arc<Object>> {
fn eval_literal(literal: &Literal) -> Result<Rc<Object>> {
let result = match literal {
Literal::Integer(integer) => Object::Integer(integer.value),
Literal::Boolean(Boolean { value, .. }) => Object::Boolean(*value),
Expand All @@ -230,11 +270,7 @@ fn eval_literal(literal: &Literal) -> Result<Arc<Object>> {
}

fn native_bool_to_bool_object(input: bool) -> Object {
if input {
TRUE.clone()
} else {
FALSE.clone()
}
Object::Boolean(input)
}

#[cfg(test)]
Expand Down Expand Up @@ -349,7 +385,7 @@ mod tests {
if let Some(expected) = expected {
assert_integer_object(evaluated, expected)?;
} else {
assert_eq!(*evaluated, *NULL);
assert_eq!(*evaluated, Object::Null);
}
}

Expand All @@ -375,21 +411,37 @@ mod tests {
Ok(())
}

fn assert_eval(input: &str) -> Result<Arc<Object>, Error> {
let env = Arc::new(RefCell::new(Environment::new()));
#[test]
fn test_eval_functions() -> Result<(), Error> {
let tests = vec![
("function ($x) { $x + 2; }(2);", 4)
];

for (input, expected) in tests {
let evaluated = assert_eval(input)?;

dbg!(&evaluated);
assert_integer_object(evaluated, expected)?;
}

Ok(())
}

fn assert_eval(input: &str) -> Result<Rc<Object>, Error> {
let env = Rc::new(RefCell::new(Environment::new()));

let lexer = Lexer::new(input);
let mut parser = Parser::new(lexer);

let program = parser.parse_program();
let program = parser.parse_program()?;
parser.check_errors()?;

let evaluated = eval(Node::Program(program), &env);

evaluated
}

fn assert_boolean_literal_object(object: Arc<Object>, expected: bool) -> Result<(), Error> {
fn assert_boolean_literal_object(object: Rc<Object>, expected: bool) -> Result<(), Error> {
if let Object::Boolean(boolean) = *object {
assert_eq!(boolean, expected);
} else {
Expand All @@ -399,7 +451,7 @@ mod tests {
Ok(())
}

fn assert_integer_object(object: Arc<Object>, expected: i64) -> Result<(), Error> {
fn assert_integer_object(object: Rc<Object>, expected: i64) -> Result<(), Error> {
if let Object::Integer(integer) = *object {
assert_eq!(integer, expected);
} else {
Expand Down
Loading

0 comments on commit 57f178f

Please sign in to comment.