diff --git a/src/eval.rs b/src/eval.rs index bdc2351..1125aa4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -60,10 +60,11 @@ fn eval_inner( funcs.clone(), sym_loose, first_item, + true, mret.cdr ) { Ok(ctr) => { - mret.car = ctr + mret.car = ctr; }, Err(err) => { return Err(err) @@ -76,15 +77,18 @@ fn eval_inner( funcs.clone(), sym_loose, false, - RefCell::new(Rc::clone(Ctr::None)) + false, + Ctr::None ) { Ok(ctr) => { - mret.cdr = ctr + mret.cdr = ctr; }, Err(err) => { return Err(err) } } + + return Ok(ret) } fn process_ctr( @@ -93,7 +97,8 @@ fn process_ctr( funcs: Rc>, sym_loose: bool, first_item: bool, - rest: Ast + is_car: bool, + rest: Ctr ) -> Result { /* LOGIC: * 1. if symbol, unwrap (DEEP COPY) @@ -106,39 +111,52 @@ fn process_ctr( match ctr { Ctr::Symbol(token) => { let mut tok = token; - if let Some(s) = vars.borrow().get(token) { + if let Some(s) = vars.borrow().get(&tok) { // is function, or variable alias? if first_item { - if let Ctr::Symbol(t) = s { - if let Some(f) = funcs.borrow().get(t) { + if let Ctr::Symbol(t) = *s.clone() { + if let Some(f) = funcs.borrow().get(&t) { + // leave this set for the function call case below tok = t; } } // is a basic value. } else { - return Ok((*s).clone()) + return Ok(*s.clone()) } - // else call function + // variable not found case } else if !first_item && !sym_loose { - return Err("variable not found") + return Err(format!("variable '{}' not found", tok).to_string()) } + // function call case if first_item { - if let Some(f) = funcs.borrow().get(tok) { - match func_call(f, rest, vars.clone(), funcs.clone()) { - Ok(a) => Ok(Ctr::Seg(a.borrow().clone())), - Err(s) => Err(s) + if let Some(f) = funcs.borrow().get(&tok) { + if let Ctr::Seg(args) = rest { + match func_call(*f, args, vars.clone(), funcs.clone()) { + Ok(a) => return Ok(a.clone()), + Err(s) => return Err(s) + } + } else { + return Err("evaluation: args to function not a list".to_string()) } + } else { + return Err(format!("function '{}' not defined", tok).to_string()) } + + // sym_loose and not function call + } else { + return Ok(ctr.clone()) } }, Ctr::Seg(tree) => { - match eval(tree, vars, funcs, sym_loose) { + // if list is_car then we need to set first_item to true + match eval_inner(tree, vars, funcs, sym_loose, is_car) { Ok(ast) => { - Ok(ast.borrow()) + Ok(Ctr::Seg(ast)) }, Err(e) => { Err(e) diff --git a/src/func.rs b/src/func.rs index e118856..147b727 100644 --- a/src/func.rs +++ b/src/func.rs @@ -26,7 +26,7 @@ use crate::eval::eval; pub type FTable = HashMap>>; // Standardized function signature for stdlib functions -pub type InternalOperation = fn(Ast, Rc>, Rc>) -> Ast; +pub type InternalOperation = fn(Ast, Rc>, Rc>) -> Ctr; pub struct ExternalOperation { // Un-evaluated abstract syntax tree // TODO: Intermediate evaluation to simplify branches with no argument in them @@ -76,7 +76,7 @@ pub fn func_call( args: Ast, vars: Rc>, funcs: Rc> -) -> Result { +) -> Result { let called_func = function.borrow_mut(); let mut n_args: Ast = args.clone(); if !called_func.eval_lazy { @@ -151,15 +151,22 @@ pub fn func_call( match &called_func.function { Operation::Internal(f) => Ok((f)(n_args, vars, funcs)), Operation::External(f) => { - let mut temp = vars.borrow().clone(); for n in 0..f.arg_syms.len() { - temp.insert( + vars.borrow().insert( f.arg_syms[n].clone(), Rc::new(list_idx(n_args.clone(), n as u128)) ); } - eval(f.ast.clone(), Rc::new(RefCell::new(temp)), funcs, called_func.loose_syms) + let result = eval(f.ast.clone(), vars.clone(), funcs, called_func.loose_syms); + for n in 0..f.arg_syms.len() { + vars.borrow().remove(&f.arg_syms[n].clone()); + } + + match result { + Ok(r) => Ok(r.borrow().car), + Err(e) => Err(e) + } } } } diff --git a/tests/test_func.rs b/tests/test_func.rs index 05cd14c..39a3470 100644 --- a/tests/test_func.rs +++ b/tests/test_func.rs @@ -20,7 +20,7 @@ mod func_tests { is_bool = true; } - new_ast(Ctr::Bool(is_bool), Ctr::None) + Ctr::Bool(is_bool) } ) }; @@ -42,8 +42,8 @@ mod func_tests { return; } - if let Ok(ast) = func_call(func, args, vt, ft) { - match &ast.borrow().car { + if let Ok(ret) = func_call(func, args, vt, ft) { + match ret { Ctr::Bool(b) => assert!(b), _ => { print!("invalid return from func!");