diff --git a/src/env.rs b/src/env.rs index 704de73..845c0a9 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,20 +1,28 @@ 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() -> Env<'a> { + Env { + vars: HashMap::new(), + parent: None, + } + } + + pub fn clone(&self) -> Env<'a> { + Env { + vars: self.vars.clone(), + parent: self.parent, + } } - pub fn extend(parent: Rc>) -> Env { + pub fn extend(parent: &'a Self) -> Env<'a> { Env { vars: HashMap::new(), parent: Some(parent), @@ -24,10 +32,7 @@ impl Env { 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 d21c10b..975c097 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() { @@ -157,7 +155,7 @@ fn eval_function_definition(list: &Vec) -> Result { Ok(Object::Lambda(params, body)) } -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)); } @@ -187,8 +185,8 @@ fn eval_map(list: &Vec, env: &mut Rc>) -> Result, 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)); } @@ -226,8 +224,8 @@ fn eval_filter(list: &Vec, env: &mut Rc>) -> Result, 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)); } @@ -279,13 +277,11 @@ fn eval_reduce(list: &Vec, env: &mut Rc>) -> Result, env: &mut Rc>) -> Result>) -> Result { +fn eval_begin(list: &Vec, env: &mut Env) -> Result { + let mut result = Object::Void; + let mut new_env = Env::extend(env); + + for obj in list[1..].iter() { + result = eval_obj(obj, &mut new_env)?; + } + Ok(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() { @@ -308,11 +314,12 @@ fn eval_symbol(s: &str, env: &mut Rc>) -> Result { Ok(val.unwrap().clone()) } -fn eval_keyword(list: &Vec, env: &mut Rc>) -> Result { +fn eval_keyword(list: &Vec, env: &mut Env) -> Result { let head = &list[0]; match head { Object::Keyword(s) => match s.as_str() { "define" => return eval_define(&list, env), + "begin" => return eval_begin(&list, env), "list" => return eval_list_data(&list, env), "print" => return print_list(&list, env), "lambda" => return eval_function_definition(&list), @@ -327,9 +334,10 @@ fn eval_keyword(list: &Vec, env: &mut Rc>) -> Result>) -> Result { +fn eval_obj(obj: &Object, env: &mut Env) -> Result { + println!("Evaluating: with environment {:?}", env); let mut current_obj = Box::new(obj.clone()); - let mut current_env = env.clone(); + let mut current_env = env; loop { match *current_obj { Object::List(list) => { @@ -360,7 +368,7 @@ fn eval_obj(obj: &Object, env: &mut Rc>) -> Result continue; } Object::Symbol(s) => { - let lamdba = current_env.borrow_mut().get(s); + let lamdba = current_env.get(s); if lamdba.is_none() { return Err(format!("Unbound function: {}", s)); } @@ -368,14 +376,13 @@ fn eval_obj(obj: &Object, env: &mut Rc>) -> Result let func = lamdba.unwrap(); match func { Object::Lambda(params, body) => { - let new_env = - Rc::new(RefCell::new(Env::extend(current_env.clone()))); + let mut new_env = current_env.clone(); for (i, param) in params.iter().enumerate() { let val = eval_obj(&list[i + 1], &mut current_env)?; - new_env.borrow_mut().set(param, val); + new_env.set(param, val); } current_obj = Box::new(Object::List(body)); - current_env = new_env.clone(); + *current_env = new_env; continue; } _ => return Err(format!("Not a lambda: {}", s)), @@ -409,7 +416,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())); @@ -423,63 +430,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 \") @@ -498,28 +505,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) @@ -534,7 +541,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) @@ -549,7 +556,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) @@ -563,7 +570,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))) @@ -587,7 +594,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)))) @@ -609,7 +616,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)))) @@ -624,35 +631,52 @@ 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)))))) + (define fib + (lambda (n) + (begin + (define n1 n) + (if (< n1 3) + 1 + (+ (fib (- n1 1)) (fib (- n1 2))) + ) + ) + ) + ) (fib 10) ) "; let result = eval(program, &mut env).unwrap(); - assert_eq!(result, Object::List(vec![Object::Integer((89) as i64)])); + assert_eq!(result, Object::List(vec![Object::Integer((55) as i64)])); } #[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)))))) - (fact 5) + (define fact + (lambda (n) + (if (< n 1) + 1 + (* n (fact (- n 1))) + ) + ) + ) + (fact 6) ) "; let result = eval(program, &mut env).unwrap(); - assert_eq!(result, Object::List(vec![Object::Integer((120) as i64)])); + assert_eq!(result, Object::List(vec![Object::Integer((720) as i64)])); } #[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) @@ -671,9 +695,8 @@ mod tests { } #[test] - fn test_tail_recursion() - { - let mut env = Rc::new(RefCell::new(Env::new())); + fn test_tail_recursion() { + let mut env = Env::new(); let program = " ( (define sum-n @@ -689,9 +712,8 @@ mod tests { } #[test] - fn test_tail_recursive_factorial() - { - let mut env = Rc::new(RefCell::new(Env::new())); + fn test_tail_recursive_factorial() { + let mut env = Env::new(); let program = " ( (define fact @@ -704,13 +726,15 @@ mod tests { "; let result = eval(program, &mut env).unwrap(); - assert_eq!(result, Object::List(vec![Object::Integer((3628800) as i64)])); + assert_eq!( + result, + Object::List(vec![Object::Integer((3628800) as i64)]) + ); } #[test] - fn test_tail_recursive_fibonnaci() - { - let mut env = Rc::new(RefCell::new(Env::new())); + fn test_tail_recursive_fibonnaci() { + let mut env = Env::new(); let program = " ( (define fib diff --git a/src/lexer.rs b/src/lexer.rs index a452d0f..fd57ba1 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -101,9 +101,8 @@ pub fn tokenize(input: &str) -> Result, TokenError> { } let token = match word.as_str() { - "define" | "list" | "print" | "lambda" | "map" | "filter" | "reduce" => { - Token::Keyword(word) - } + "define" | "list" | "print" | "lambda" | "map" | "filter" | "reduce" + | "begin" => Token::Keyword(word), "if" => Token::If, "+" | "-" | "*" | "/" | "%" | "<" | ">" | "=" | "!=" | "&" | "|" => { Token::BinaryOp(word) diff --git a/src/main.rs b/src/main.rs index adf7b7b..65b4222 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,14 +6,12 @@ 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();