Files
simple-rust-tests/__lang/monkey-rs/src/evaluator.rs
2022-06-02 00:32:03 +08:00

495 lines
18 KiB
Rust

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<RefCell<Environment>>) -> 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<RefCell<Environment>>) -> 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<RefCell<Environment>>) -> 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<RefCell<Environment>>) -> 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<Box<BlockStatement>>, env: &mut Rc<RefCell<Environment>>) -> 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<Expression>, env: &mut Rc<RefCell<Environment>>) -> Vec<Object> {
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<String>, param_objs: &Vec<Object>,
func_block: &BlockStatement,
env: &mut Rc<RefCell<Environment>>) -> 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<RefCell<Environment>>) -> 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<Expression>, env: &mut Rc<RefCell<Environment>>) -> 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<Object>, 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<Object, Object>, 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<Expression>, idx_expr: &Box<Expression>,
env: &mut Rc<RefCell<Environment>>) -> 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<Expression>, parameters: &Vec<Expression>,
env: &mut Rc<RefCell<Environment>>) -> 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(&params, &param_objs, &block, &mut func_env)
}
Object::FunctionInBuilt(_) => eval_inbuilt_function(&func_obj, &param_objs),
_ => panic!("Invalid object type {}, expected function object", func_obj)
}
}
pub fn eval_expression(expr: &Expression, env: &mut Rc<RefCell<Environment>>) -> 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<RefCell<Environment>>) -> 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<RefCell<Environment>>) -> Object {
eval_expression(expr, env)
}
pub fn eval_program(program: &Program, env: &mut Rc<RefCell<Environment>>) -> 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<TestCase>) {
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);
}
}