mod func_tests { use relish::ast::lex; use relish::ast::{SYM_TABLE, Type, UserFn}; use relish::ast::{Args, Symbol, Ctr, Seg, ValueType}; #[test] fn decl_and_call_internal_func() { let mut table_handle = SYM_TABLE.lock().unwrap(); let test_internal_func: Symbol = Symbol { name: String::from("test_func_in"), has_undefined_symbols: false, args: Args::Strict(vec![Type::Bool]), value: ValueType::Internal(Box::new( |a: &Seg| -> Ctr { let inner = a; let mut is_bool = false; if let Ctr::Bool(_) = *inner.car { is_bool = true; } Ctr::Bool(is_bool) }, )), }; let args = Seg::from( Box::new(Ctr::Bool(true)), Box::new(Ctr::None) ); table_handle.insert(String::from("test_func_in"), test_internal_func); let func: &Symbol; if let Some(f) = table_handle.get(&"test_func_in".to_string()) { func = f; } else { print!("failed to retrieve function!"); assert!(false); return; } if let Ok(ret) = func.call(&args) { match *ret { Ctr::Bool(b) => assert!(b), _ => { print!("invalid return from func!"); assert!(false); } } } else { print!("call to function failed!"); assert!(false); } } #[test] fn decl_and_call_external_func_singlet() { let mut table_handle = SYM_TABLE.lock().unwrap(); match lex(&"((input))".to_string()) { Err(e) => panic!("{}", e), Ok(finner) => { let test_external_func: Symbol = Symbol { name: String::from("echo"), has_undefined_symbols: false, args: Args::Lazy(1), value: ValueType::FuncForm(UserFn{ arg_syms: vec!["input".to_string()], ast: finner, }), }; let args = Seg::from( Box::new(Ctr::String("test".to_string())), Box::new(Ctr::None) ); table_handle.insert(String::from("test_func_in"), test_external_func); let func: &Symbol; if let Some(f) = table_handle.get(&"test_func_in".to_string()) { func = f; } else { print!("failed to retrieve function!"); assert!(false); return; } match func.call(&args) { Ok(ret) => match *ret { Ctr::String(b) => assert!(b == "test"), _ => { print!("Invalid return from func. Got {:?}\n", ret); assert!(false); } }, Err(e) => { print!("Call to function failed: {}\n", e); assert!(false); } } } } } #[test] fn decl_and_call_external_func_multi_body() { let mut table_handle = SYM_TABLE.lock().unwrap(); match lex(&"((input) (input))".to_string()) { Err(e) => panic!("{}", e), Ok(finner) => { let test_external_func: Symbol = Symbol{ name: String::from("echo_2"), has_undefined_symbols: false, args: Args::Lazy(1), value: ValueType::FuncForm(UserFn{ arg_syms: vec!["input".to_string()], ast: finner, }), }; let args = Seg::from( Box::new(Ctr::String("test".to_string())), Box::new(Ctr::None) ); table_handle.insert(String::from("echo_2"), test_external_func); let func: &Symbol; if let Some(f) = table_handle.get(&"echo_2".to_string()) { func = f; } else { print!("failed to retrieve function!"); assert!(false); return; } match func.call(&args) { Ok(ret) => assert_eq!(ret.to_string(), "(\"test\" \"test\")"), Err(e) => { print!("Call to function failed: {}\n", e); assert!(false); } } } } } #[test] fn decl_and_call_func_with_nested_call() { let mut table_handle = SYM_TABLE.lock().unwrap(); let inner_func: Symbol = Symbol { name: String::from("test_inner"), has_undefined_symbols: false, args: Args::Strict(vec![Type::Bool]), value: ValueType::Internal(Box::new( |a: &Seg| -> Ctr { let inner = a; if let Ctr::Bool(b) = *inner.car { if b { Ctr::String("test".to_string()) } else { Ctr::None } } else { Ctr::None } }, )), }; match lex(&"((test_inner true))".to_string()) { Err(e) => panic!("{}", e), Ok(finner) => { let outer_func: Symbol = Symbol { name: String::from("test_outer"), has_undefined_symbols: false, args: Args::Lazy(1), value: ValueType::FuncForm(UserFn{ arg_syms: vec!["input".to_string()], ast: finner, }), }; let args = Seg::from( Box::new(Ctr::Bool(true)), Box::new(Ctr::None) ); table_handle.insert(String::from("test_inner"), inner_func); table_handle.insert(String::from("test_outer"), outer_func); let func: &Symbol; if let Some(f) = table_handle.get(&"test_outer".to_string()) { func = f; } else { print!("failed to retrieve function!"); assert!(false); return; } match func.call(&args) { Ok(ret) => match *ret { Ctr::String(b) => assert!(b == "test"), _ => { print!("Invalid return from func. Got {:?}\n", ret); assert!(false); } }, Err(e) => { print!("Call to function failed: {}\n", e); assert!(false); } } } } } /* // TODO: These tests need completion! #[test] fn eval_lazy_func_call() { } #[test] fn sym_loose_func_call() { } #[test] fn too_many_args() { } #[test] fn not_enough_args() { } #[test] fn bad_eval_arg() { } #[test] fn bad_eval_fn_body() { }*/ }