diff --git a/src/env.rs b/src/env.rs index 704de73..b08c492 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,33 +1,31 @@ use crate::object::Object; -use std::cell::RefCell; use std::collections::HashMap; -use std::rc::Rc; #[derive(Debug, PartialEq, Default)] -pub struct Env { - parent: Option>>, +pub struct Env<'a> { + parent: Option<&'a Env<'a>>, vars: HashMap, } -impl Env { - pub fn new() -> Self { - Default::default() +impl<'a> Env<'a> { + pub fn new() -> Box> { + Box::new(Env { + vars: HashMap::new(), + parent: None, + }) } - pub fn extend(parent: Rc>) -> Env { - Env { + pub fn extend(parent: &'a Self) -> Box> { + Box::new(Env { vars: HashMap::new(), parent: Some(parent), - } + }) } pub fn get(&self, name: &str) -> Option { match self.vars.get(name) { Some(value) => Some(value.clone()), - None => self - .parent - .as_ref() - .and_then(|o| o.borrow().get(name).clone()), + None => self.parent.and_then(|parent| parent.get(name)), } } diff --git a/src/eval.rs b/src/eval.rs index 2b602b7..7bb6454 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,11 +1,9 @@ use crate::env::*; use crate::object::*; use crate::parser::*; -use std::cell::RefCell; use std::cmp::Ordering; -use std::rc::Rc; -fn print_list(list: &Vec, env: &mut Rc>) -> Result { +fn print_list(list: &Vec, env: &mut Env) -> Result { let mut new_list = Vec::new(); for obj in list[1..].iter() { @@ -18,7 +16,7 @@ fn print_list(list: &Vec, env: &mut Rc>) -> Result, env: &mut Rc>) -> Result { +fn eval_binary_op(list: &Vec, env: &mut Env) -> Result { if list.len() != 3 { return Err(format!("Invalid number of arguments for infix operator")); } @@ -112,7 +110,7 @@ fn eval_binary_op(list: &Vec, env: &mut Rc>) -> Result, env: &mut Rc>) -> Result { +fn eval_define(list: &Vec, env: &mut Env) -> Result { if list.len() != 3 { return Err(format!("Invalid number of arguments for define")); } @@ -122,11 +120,11 @@ fn eval_define(list: &Vec, env: &mut Rc>) -> Result return Err(format!("Invalid define")), }; let val = eval_obj(&list[2], env)?; - env.borrow_mut().set(&sym, val); + env.set(&sym, val); Ok(Object::Void) } -fn eval_list_data(list: &Vec, env: &mut Rc>) -> Result { +fn eval_list_data(list: &Vec, env: &mut Env) -> Result { let mut new_list = Vec::new(); for obj in list[1..].iter() { @@ -135,7 +133,7 @@ fn eval_list_data(list: &Vec, env: &mut Rc>) -> Result, env: &mut Rc>) -> Result { +fn eval_if(list: &Vec, env: &mut Env) -> Result { if list.len() != 4 { return Err(format!("Invalid number of arguments for if statement")); } @@ -175,12 +173,8 @@ fn eval_function_definition(list: &Vec) -> Result { Ok(Object::Lambda(params, body)) } -fn eval_function_call( - s: &str, - list: &Vec, - env: &mut Rc>, -) -> Result { - let lamdba = env.borrow_mut().get(s); +fn eval_function_call(s: &str, list: &Vec, env: &mut Env) -> Result { + let lamdba = env.get(s); if lamdba.is_none() { return Err(format!("Unbound function: {}", s)); } @@ -188,23 +182,23 @@ fn eval_function_call( let func = lamdba.unwrap(); match func { Object::Lambda(params, body) => { - let mut new_env = Rc::new(RefCell::new(Env::extend(env.clone()))); + let mut new_env = Env::extend(env); for (i, param) in params.iter().enumerate() { - let val = eval_obj(&list[i + 1], env)?; - new_env.borrow_mut().set(param, val); + let val = eval_obj(&list[i + 1], &mut *new_env)?; + new_env.set(param, val); } - return eval_obj(&Object::List(body), &mut new_env); + return eval_obj(&Object::List(body), &mut *new_env); } _ => return Err(format!("Not a lambda: {}", s)), } } -fn eval_symbol(s: &str, env: &mut Rc>) -> Result { +fn eval_symbol(s: &str, env: &mut Env) -> Result { let val = match s { "#t" => return Ok(Object::Bool(true)), "#f" => return Ok(Object::Bool(false)), "#nil" => return Ok(Object::Void), - _ => env.borrow_mut().get(s), + _ => env.get(s), }; if val.is_none() { @@ -214,7 +208,7 @@ fn eval_symbol(s: &str, env: &mut Rc>) -> Result { Ok(val.unwrap().clone()) } -fn eval_map(list: &Vec, env: &mut Rc>) -> Result { +fn eval_map(list: &Vec, env: &mut Env) -> Result { if list.len() != 3 { return Err(format!("Invalid number of arguments for map {:?}", list)); } @@ -244,16 +238,16 @@ fn eval_map(list: &Vec, env: &mut Rc>) -> Result, env: &mut Rc>) -> Result { +fn eval_filter(list: &Vec, env: &mut Env) -> Result { if list.len() != 3 { return Err(format!("Invalid number of arguments for filter {:?}", list)); } @@ -283,10 +277,10 @@ fn eval_filter(list: &Vec, env: &mut Rc>) -> Result b, _ => return Err(format!("Invalid filter result: {}", result_obj)), @@ -298,7 +292,7 @@ fn eval_filter(list: &Vec, env: &mut Rc>) -> Result, env: &mut Rc>) -> Result { +fn eval_reduce(list: &Vec, env: &mut Env) -> Result { if list.len() != 3 { return Err(format!("Invalid number of arguments for reduce {:?}", list)); } @@ -336,20 +330,18 @@ fn eval_reduce(list: &Vec, env: &mut Rc>) -> Result, env: &mut Rc>) -> Result { +fn eval_list(list: &Vec, env: &mut Env) -> Result { let head = &list[0]; match head { Object::Symbol(s) => match s.as_str() { @@ -380,7 +372,7 @@ fn eval_list(list: &Vec, env: &mut Rc>) -> Result>) -> Result { +fn eval_obj(obj: &Object, env: &mut Env) -> Result { match obj { Object::List(list) => eval_list(list, env), Object::Void => Ok(Object::Void), @@ -394,7 +386,7 @@ fn eval_obj(obj: &Object, env: &mut Rc>) -> Result } } -pub fn eval(program: &str, env: &mut Rc>) -> Result { +pub fn eval(program: &str, env: &mut Env) -> Result { let parsed_list = parse(program); if parsed_list.is_err() { return Err(format!("{}", parsed_list.err().unwrap())); @@ -408,63 +400,63 @@ mod tests { #[test] fn test_simple_add() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(+ 1 2)", &mut env).unwrap(); assert_eq!(result, Object::Integer(3)); } #[test] fn test_simple_sub() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(- 1.0 2)", &mut env).unwrap(); assert_eq!(result, Object::Float(-1.0)); } #[test] fn test_str_add() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(+ \"Raleigh\" \"Durham\")", &mut env).unwrap(); assert_eq!(result, Object::String("RaleighDurham".to_string())); } #[test] fn test_str_eq_false() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(= \"Raleigh\" \"Durham\")", &mut env).unwrap(); assert_eq!(result, Object::Bool(false)); } #[test] fn test_str_eq_true() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(= \"Raleigh\" \"Raleigh\")", &mut env).unwrap(); assert_eq!(result, Object::Bool(true)); } #[test] fn test_greater_than_str() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(> \"Raleigh\" \"Durham\")", &mut env).unwrap(); assert_eq!(result, Object::Bool(true)); } #[test] fn test_less_than_str() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(< \"abcd\" \"abef\")", &mut env).unwrap(); assert_eq!(result, Object::Bool(true)); } #[test] fn test_str_with_spaces() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(+ \"Raleigh \" \"Durham\")", &mut env).unwrap(); assert_eq!(result, Object::String("Raleigh Durham".to_string())); } #[test] fn test_str_with_spaces_2() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let program = " ( (define fruits \"apples mangoes bananas \") @@ -483,28 +475,28 @@ mod tests { #[test] fn test_greater_than_int() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(> 10 20)", &mut env).unwrap(); assert_eq!(result, Object::Bool(false)); } #[test] fn test_less_than_int() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(< 21.0 20.0)", &mut env).unwrap(); assert_eq!(result, Object::Bool(false)); } #[test] fn test_modulo() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let result = eval("(% 21.0 20.0)", &mut env).unwrap(); assert_eq!(result, Object::Float(1.0)); } #[test] fn test_area_of_a_circle_float() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let program = "( (define r 5.0) (define pi 3.14) @@ -519,7 +511,7 @@ mod tests { #[test] fn test_area_of_a_circle() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let program = "( (define r 10) (define pi 314) @@ -534,7 +526,7 @@ mod tests { #[test] fn test_sqr_function() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let program = "( (define sqr (lambda (r) (* r r))) (sqr 10) @@ -548,7 +540,7 @@ mod tests { #[test] fn test_map() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let program = " ( (define sqr (lambda (r) (* r r))) @@ -572,7 +564,7 @@ mod tests { #[test] fn test_filter() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let program = " ( (define odd (lambda (v) (= 1 (% v 2)))) @@ -594,7 +586,7 @@ mod tests { #[test] fn test_reduce() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let program = " ( (define odd (lambda (v) (= 1 (% v 2)))) @@ -609,7 +601,7 @@ mod tests { #[test] fn test_fibonaci() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let program = " ( (define fib (lambda (n) (if (< n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))) @@ -623,7 +615,7 @@ mod tests { #[test] fn test_factorial() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let program = " ( (define fact (lambda (n) (if (< n 1) 1 (* n (fact (- n 1)))))) @@ -637,7 +629,7 @@ mod tests { #[test] fn test_circle_area_function() { - let mut env = Rc::new(RefCell::new(Env::new())); + let mut env = Env::new(); let program = " ( (define pi 314) diff --git a/src/main.rs b/src/main.rs index adf7b7b..2b5753b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,14 +6,11 @@ mod parser; use linefeed::{Interface, ReadResult}; use object::Object; -use std::cell::RefCell; -use std::rc::Rc; - const PROMPT: &str = "lisp-rs> "; fn main() -> Result<(), Box> { let reader = Interface::new(PROMPT).unwrap(); - let mut env = Rc::new(RefCell::new(env::Env::new())); + let mut env = env::Env::new(); reader.set_prompt(format!("{}", PROMPT).as_ref()).unwrap();