use crate::ast::*; use crate::object::Object; use crate::environment::Environment; use crate::inbuilt::{get_inbuilt_function, eval_inbuilt_function}; use std::cell::RefCell; use std::rc::Rc; use std::collections::HashMap; pub fn eval_identifier(identifier: &Expression, env: &Rc>) -> Object { match identifier { Expression::Identifier(i) => { let id = env.borrow_mut().get(i.as_str()); if id.is_some() { return id.unwrap(); } let inbuilt_func = get_inbuilt_function(i.as_str()); if inbuilt_func.is_some() { return inbuilt_func.unwrap(); } } _ => panic!("Expected identifier") } Object::Nil } pub fn eval_prefix_expression(prefix: &Prefix, expression: &Expression, env: &mut Rc>) -> Object { let expr_val = eval_expression(expression, env); match prefix { Prefix::Minus => { match expr_val { Object::Integer(i) => Object::Integer(-1 * i), _ => panic!("Invalid expression {} in prefix expression, expected integer", expr_val) } } Prefix::Bang => { match expr_val { Object::Boolean(b) => Object::Boolean(!b), _ => panic!("Invalid expression {} in prefix expression, expected boolean", expr_val) } } } } pub fn eval_infix_expression(infix: &Infix, left: &Expression, right: &Expression, env: &mut Rc>) -> Object { let left_obj = eval_expression(left, env); let right_obj = eval_expression(right, env); match left_obj { Object::Integer(i) => { let left_int = i; let right_int; match right_obj { Object::Integer(i) => { right_int = i; match infix { Infix::Plus => Object::Integer(left_int + right_int), Infix::Minus => Object::Integer(left_int - right_int), Infix::Asterisk => Object::Integer(left_int * right_int), Infix::Slash => Object::Integer(left_int / right_int), Infix::NotEq => Object::Boolean(left_int != right_int), Infix::Eq => Object::Boolean(left_int == right_int), Infix::Gt => Object::Boolean(left_int > right_int), Infix::Lt => Object::Boolean(left_int < right_int), _ => panic!("Inintid op {}", infix) } } _ => panic!("Expected integer {}", right_obj), } } Object::String(s) => { let left_str = s; let right_str; match right_obj { Object::String(s) => { right_str = s; match infix { Infix::Plus => Object::String(left_str + &*right_str), _ => panic!("Invalid op {} for strings", infix) } } _ => panic!("Expected String{}", right_obj), } } _ => panic!("Invalid value in expression {}, expected int", left_obj), } } pub fn eval_block_statement(block: &BlockStatement, env: &mut Rc>) -> Object { let mut val = Object::Nil; for stmt in &block.stmts { val = match stmt { Statement::Let(x, expr) => eval_let_statement(x.to_string(), &*expr, env), Statement::Return(Some(x)) => { return eval_return_statement(&*x, env); } Statement::Return(None) => { return Object::Nil; } Statement::Expression(expr) => eval_expression(&*expr, env), } } val } pub fn eval_if_expression(expr: &Expression, true_block: &BlockStatement, false_block: &Option>, env: &mut Rc>) -> Object { let expr_obj = eval_expression(expr, env); let expr_val = match expr_obj { Object::Boolean(v) => v, _ => panic!("Expected boolean expression in if statement, found {}", expr_obj) }; if expr_val { eval_block_statement(true_block, env) } else if false_block.is_some() { eval_block_statement(false_block.as_ref().unwrap().as_ref(), env) } else { Object::Nil } } pub fn eval_function_parameters(params: &Vec, env: &mut Rc>) -> Vec { let mut param_objs = vec![]; for param in params.iter() { let param_obj = eval_expression(param, env); if param_obj == Object::Nil { panic!("Unable to evaluate parameter {}", param); } param_objs.push(eval_expression(param, env)) } param_objs } pub fn eval_user_defined_function_call(func_params: &Vec, param_objs: &Vec, func_block: &BlockStatement, env: &mut Rc>) -> Object { let mut func_new_env = Rc::new(RefCell::new(Environment::extend(env.clone()))); let mut idx = 0; while idx < param_objs.len() { func_new_env.borrow_mut().set(&*func_params[idx], param_objs[idx].clone()); idx += 1; } eval_block_statement(&func_block, &mut func_new_env) } pub fn eval_dict_literal(dict_expr: &Vec<(Expression, Expression)>, env: &mut Rc>) -> Object { let mut dict = HashMap::new(); for (key_expr, val_expr) in dict_expr { let key = eval_expression(key_expr, env); let val = eval_expression(val_expr, env); dict.insert(key, val); } Object::Dict(dict) } pub fn eval_array_literal(member_expr: &Vec, env: &mut Rc>) -> Object { let mut members = vec![]; for mem in member_expr.iter() { members.push(eval_expression(mem, env)); } Object::Array(members) } pub fn eval_arr_idx(arr: &Vec, idx: &Object) -> Object { match idx { Object::Integer(index) => { if *index as usize > arr.len() - 1 { panic!("Array index {} greater that array size {}", idx, arr.len()); } let obj = arr.get(*index as usize).unwrap().clone(); obj } _ => panic!("Invalid array index {}, expected a positive integer", idx), } } pub fn eval_dict_idx(dict: &HashMap, idx: &Object) -> Object { let mut ret_val = Object::Nil; if dict.contains_key(idx) { ret_val = dict.get(idx).unwrap().clone(); } ret_val } pub fn eval_index(container_expr: &Box, idx_expr: &Box, env: &mut Rc>) -> Object { let container = eval_expression(container_expr, env); let idx = eval_expression(idx_expr, env); match container { Object::Array(arr) => eval_arr_idx(&arr, &idx), Object::Dict(dict) => eval_dict_idx(&dict, &idx), _ => panic!("Expected array or dictionary got {}", container.to_string()), } } pub fn eval_function_call(func_expr: &Box, parameters: &Vec, env: &mut Rc>) -> Object { let func_obj = eval_expression(func_expr, env); let param_objs = eval_function_parameters(parameters, env); match func_obj { Object::FunctionLiteral(params, block, mut func_env) => { if param_objs.len() != params.len() { panic!("Did not find the expected number of arguments for the function"); } eval_user_defined_function_call(¶ms, ¶m_objs, &block, &mut func_env) } Object::FunctionInBuilt(_) => eval_inbuilt_function(&func_obj, ¶m_objs), _ => panic!("Invalid object type {}, expected function object", func_obj) } } pub fn eval_expression(expr: &Expression, env: &mut Rc>) -> Object { match expr { Expression::IntegerLiteral(i) => Object::Integer(*i), Expression::Identifier(_s) => eval_identifier(expr, env), Expression::String(s) => Object::String(s.to_string()), Expression::Boolean(b) => Object::Boolean(*b), Expression::Prefix(prefix, expr) => eval_prefix_expression(prefix, expr, env), Expression::Infix(infix, left, right) => eval_infix_expression(infix, left, right, env), Expression::If(expr, true_block, false_block) => eval_if_expression(expr, true_block, false_block, env), Expression::ArrayLiteral(arr) => eval_array_literal(arr, env), Expression::DictionaryLiteral(dict) => eval_dict_literal(dict, env), Expression::Index(arr, idx) => eval_index(arr, idx, env), Expression::FunctionLiteral(params, block) => Object::FunctionLiteral(params.clone(), *block.clone(), env.clone()), Expression::Call(func, params) => eval_function_call(func, params, env), } } pub fn eval_let_statement(identifier: String, expr: &Expression, env: &mut Rc>) -> Object { let expr_val = eval_expression(expr, env); env.borrow_mut().set(identifier.as_str(), expr_val); Object::Nil } pub fn eval_return_statement(expr: &Expression, env: &mut Rc>) -> Object { eval_expression(expr, env) } pub fn eval_program(program: &Program, env: &mut Rc>) -> Object { let mut val = Object::Nil; for stmt in &program.stmts { val = match stmt { Statement::Let(id, expr) => eval_let_statement(id.to_string(), &*expr, env), Statement::Return(Some(expr)) => { return eval_return_statement(&*expr, env); } Statement::Return(None) => { return Object::Nil; } Statement::Expression(expr) => eval_expression(&*expr, env), }; } return val; } #[cfg(test)] mod tests { use crate::lexer::Lexer; use crate::parser::Parser; use crate::object::Object; use crate::environment::Environment; use crate::evaluator::*; fn test_eval_program(input: &str) -> Object { let mut env = Rc::new(RefCell::new(Environment::new())); let lexer = Lexer::new(input); let mut parser = Parser::new(lexer); let program = parser.parse_program().unwrap(); eval_program(program.as_ref(), &mut env) } struct TestCase<'a> { test_str: &'a str, val: Object, } fn check_test_cases(test_cases: Vec) { for test_case in test_cases { assert_eq!(test_eval_program(test_case.test_str), test_case.val); } } #[test] fn test_eval_integer() { let test_cases = vec![TestCase { test_str: "10", val: Object::Integer(10) }]; check_test_cases(test_cases); } #[test] fn test_eval_boolean() { let test_cases = vec![ TestCase { test_str: "true", val: Object::Boolean(true) }, TestCase { test_str: "false", val: Object::Boolean(false) }, ]; check_test_cases(test_cases); } #[test] fn test_eval_return() { let test_cases = vec![ TestCase { test_str: "return 0;", val: Object::Integer(0) }, TestCase { test_str: "return;", val: Object::Nil }, ]; check_test_cases(test_cases); } #[test] fn test_eval_prefix() { let test_cases = vec![ TestCase { test_str: "!true", val: Object::Boolean(false) }, TestCase { test_str: "!false", val: Object::Boolean(true) }, TestCase { test_str: "-1", val: Object::Integer(-1) } ]; check_test_cases(test_cases); } #[test] fn test_eval_infix() { let test_cases = vec![ TestCase { test_str: "10 > 20", val: Object::Boolean(false) }, TestCase { test_str: "-1 + 0", val: Object::Integer(-1) }, TestCase { test_str: "5 > 3", val: Object::Boolean(true) }, TestCase { test_str: "4 < 2", val: Object::Boolean(false) }, TestCase { test_str: "5 == 3", val: Object::Boolean(false) }, TestCase { test_str: "4 != 2", val: Object::Boolean(true) }, TestCase { test_str: "(2*2 + 1) == 5", val: Object::Boolean(true) }, TestCase { test_str: "(2 + 3)*2 == 10", val: Object::Boolean(true) }, TestCase { test_str: "\"ab\" + \"cd\"", val: Object::String(String::from("abcd")) }, TestCase { test_str: "\"ab\" + \"cd\" + \"ef\"", val: Object::String(String::from("abcdef")), }, ]; check_test_cases(test_cases); } #[test] fn test_eval_if_expr() { let test_cases = vec![ TestCase { test_str: "if (10 > 20) {20} else {10}", val: Object::Integer(10) }, TestCase { test_str: "if (21 > 20) {20} else {10}", val: Object::Integer(20) }, TestCase { test_str: "if (21 > 20) {20} ", val: Object::Integer(20) }, TestCase { test_str: "if (21 < 20) {20} ", val: Object::Nil }, TestCase { test_str: "if (21 > 20) {let x = 30; 20} ", val: Object::Integer(20) }, ]; check_test_cases(test_cases); } #[test] fn test_eval_let_statements() { let test_cases = vec![ TestCase { test_str: "let x = 10; if (x > 20) {20} else {10}", val: Object::Integer(10) }, TestCase { test_str: "let y = 20; if (21 > y) {20} else {10}", val: Object::Integer(20) }, TestCase { test_str: "let z = 30; z*z; ", val: Object::Integer(900) }, TestCase { test_str: "let a = 30; let b = 40; a + b", val: Object::Integer(70) }, ]; check_test_cases(test_cases); } #[test] fn test_eval_functions() { let test_cases = vec![ TestCase { test_str: "let sum = fn(x, y){ x + y;}; \ sum(10, 20);", val: Object::Integer(30), }, TestCase { test_str: "let square = fn(x){x*x}; \ square(10)", val: Object::Integer(100), }, TestCase { test_str: "let gt = fn(x, y){ \ if (!(x > y)) {\ x*x\ } else {\ y\ };\ }; \ gt(3, 2)", val: Object::Integer(2), }, TestCase { test_str: "let gt = fn(x, y){ \ if (x > y) \ {x*x} \ else {\ y\ };\ }; \ gt(3, 2)", val: Object::Integer(9), }, TestCase { test_str: "let fact = fn(x) {\ if (x > 1) {\ x*fact(x - 1);\ } else {\ x\ };\ }; \ fact(8);", val: Object::Integer(40320), }, TestCase { test_str: "let sum = fn(x,y){x + y;};\ let sqr = fn(x){let z = sum(x, x); z*z;};\ let z = sum(2, 3) + sqr(2);\ z;", val: Object::Integer(21), }, TestCase { test_str: "fn(x, y, z){x + y + z}(1, 2, 3);", val: Object::Integer(6) }, TestCase { test_str: "let a = \"wx\";\ let b = \"yz\";\ let z = a + b;\ z;", val: Object::String(String::from("wxyz")), }, ]; check_test_cases(test_cases); } #[test] fn test_closures() { let test_cases = vec![ TestCase { test_str: "let adder = fn(x){fn(x,y) { x + y; };};\ let a2 = adder(2); a2(10);", val: Object::Integer(12), }, ]; } #[test] fn test_eval_inbuilt_functions() { let test_cases = vec![ TestCase { test_str: "let x = \"cartman\"; len(x)", val: Object::Integer(7) }, TestCase { test_str: "len(\"cartman\");", val: Object::Integer(7) }, ]; check_test_cases(test_cases); } #[test] fn test_eval_arrays() { let test_cases = vec![ TestCase { test_str: "let x = [1, 2, 3]; x[2]", val: Object::Integer(3) }, TestCase { test_str: "let x = [1, 2, [1, 3]]; x[2][0]", val: Object::Integer(1) }, TestCase { test_str: "let x = [1, \"abc\", 32, 43]; x[1]", val: Object::String(String::from("abc")), }, ]; check_test_cases(test_cases); } #[test] fn test_eval_dict() { let test_cases = vec![ TestCase { test_str: "let x = {1: 2, 2: 3, 3: 4}; x[2]", val: Object::Integer(3)}, TestCase { test_str: "{1: 2, 2: 3, 3: 4}[2]", val: Object::Integer(3)}, TestCase { test_str: "let x = {1: 2, \"test\": 3, 3: 4}; x[\"test\"]", val: Object::Integer(3)}, TestCase { test_str: "let s = 3; let x = {1: 2, \"test\": 3, 3: (2*10)}; x[s]", val: Object::Integer(20)}, TestCase { test_str: "let s = \"test\"; let x = {1: 2, \"test\": \"res\", 3: (2*10)}; x[s]", val: Object::String(String::from("res"))}, ]; check_test_cases(test_cases); } }