From 93a1e06a536532505fedef7a9ee9cb4d38d5f568 Mon Sep 17 00:00:00 2001 From: Ava Hahn Date: Sat, 25 Feb 2023 23:36:30 -0800 Subject: [PATCH] all tests green Signed-off-by: Ava Hahn --- src/eval.rs | 26 ++++++++++++++++---------- src/lex.rs | 20 +++++++++++++++++++- src/sym.rs | 31 ++++++++++++++++++++++++++----- tests/test_eval.rs | 35 ++++++++++++++++++++++++++--------- tests/test_func.rs | 14 +++++++------- 5 files changed, 94 insertions(+), 32 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 52e93c6..f0e8912 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -32,7 +32,7 @@ pub fn eval ( // to be assigned from cloned/evaled data let mut car; - let mut cdr = Box::from(Ctr::None); + let mut cdr; // lets me redirect the input let mut arg_car = &ast.car; @@ -63,6 +63,12 @@ pub fn eval ( Ok(s) => car = s, Err(s) => return Err(format!("error in call to {}: {}", tok, s)), } + + if let Some(b) = syms.is_function_type(tok) { + if b { + return Ok(car); + } + } } _ => { @@ -81,24 +87,24 @@ pub fn eval ( } Ctr::Seg(ref next) => { - if let Ctr::None = *ret { - *ret = Ctr::Seg(Seg::from(car, cdr.clone())) - } else if let Ctr::Seg(ref mut s) = *ret { - s.append(Box::from(Ctr::Seg(Seg::from(car, cdr.clone())))) - } + cdr = Box::from(Ctr::None); arg_car = &next.car; arg_cdr = &next.cdr } _ => { - cdr = ast.cdr.clone(); + cdr = arg_cdr.clone(); none = true; } } - if let Ctr::None = **arg_car { - if let Ctr::None = **arg_cdr { - none = true; + if let Ctr::None = *ret { + *ret = Ctr::Seg(Seg::from(car, cdr)) + } else if let Ctr::Seg(ref mut s) = *ret { + s.append(car); + if let Ctr::None = *cdr { + } else { + s.append(cdr); } } diff --git a/src/lex.rs b/src/lex.rs index 8209fd9..a8d4bf7 100644 --- a/src/lex.rs +++ b/src/lex.rs @@ -201,7 +201,25 @@ fn process(document: &String) -> Result, String> { if is_str { Err(UNMATCHED_STR_DELIM.to_string()) } else { - Err(UNMATCHED_LIST_DELIM.to_string()) + if ref_stack.is_empty() { + let obj; + if token == "true" { + obj = Box::from(Ctr::Bool(true)); + } else if token == "false" { + obj = Box::from(Ctr::Bool(false)); + } else if let Ok(i) = token.parse::() { + obj = Box::from(Ctr::Integer(i)); + } else if let Ok(f) = token.parse::() { + obj = Box::from(Ctr::Float(f)); + } else if let Some(s) = tok_is_symbol(&token) { + obj = Box::from(Ctr::Symbol(s)); + } else { + return Err(format!("Unparsable token: {}", token)); + } + Ok(Box::new(Seg::from_mono(obj))) + } else { + Err(UNMATCHED_LIST_DELIM.to_string()) + } } } diff --git a/src/sym.rs b/src/sym.rs index d62fc6a..bafa4b3 100644 --- a/src/sym.rs +++ b/src/sym.rs @@ -88,6 +88,7 @@ impl SymTable { Some(s) => s, None => return Err(format!("undefined symbol: {}", name)), }; + self.insert(name.to_string(), symbol.clone()); let cond_args: &Seg; let outer_scope_seg_holder: Seg; @@ -100,10 +101,15 @@ impl SymTable { cond_args = &outer_scope_seg_holder; } - let res = symbol.call(cond_args, self); - self.insert(name.to_string(), symbol); + symbol.call(cond_args, self) + } - res + pub fn is_function_type(&self, name: &String) -> Option { + if let ValueType::VarForm(_) = self.get(name)?.value { + Some(false) + } else { + Some(true) + } } } @@ -144,6 +150,11 @@ impl Args { "expected {} args. Got {}.", num, called_arg_count )); + } else if let Ctr::None = *args.car { + return Err(format!( + "expected {} args. Got 0.", + num, + )); } } @@ -202,7 +213,7 @@ impl Symbol { let evaluated_args: &Seg; let outer_scope_seg_storage: Seg; let outer_scope_eval: Box; - if self.conditional_branches { + if !self.conditional_branches { let outer_scope_eval_result = eval(args, syms); // dont listen to clippy. using ? will move the value. if let Err(s) = outer_scope_eval_result { @@ -257,7 +268,17 @@ impl Symbol { Err(e) => return Err(e), } } else { - panic!("function body not in standard form!") + let temp = Seg::from_mono(iterate.car.clone()); + match eval(&temp, syms) { + Ok(ctr) => { + if let Ctr::Seg(s) = *ctr { + result = s.car.clone(); + } else { + result = ctr; + } + }, + Err(e) => return Err(e), + } } match *iterate.cdr { diff --git a/tests/test_eval.rs b/tests/test_eval.rs index cc3d3d3..06638f9 100644 --- a/tests/test_eval.rs +++ b/tests/test_eval.rs @@ -2,6 +2,29 @@ mod eval_tests { use relish::ast::{eval, lex, SymTable}; use relish::ast::{Args, Symbol, Ctr, Seg, ValueType, UserFn}; + #[test] + fn eval_simple() { + let test_doc = "(1 2)".to_string(); + let mut syms = SymTable::new(); + match lex(&test_doc) { + Err(e) => { + println!("Lexing error: {}\n", e); + assert!(false) + } + + Ok(initial_ast) => match eval(&initial_ast, &mut syms) { + Err(e) => { + println!("Evaluation error: {}\n", e); + assert!(false) + } + + Ok(reduced) => { + assert_eq!(reduced.to_string(), test_doc) + } + }, + } + } + #[test] fn eval_embedded_lists_no_funcs() { let test_doc = "(1 (1 2 3 4 5) 5)".to_string(); @@ -38,11 +61,8 @@ mod eval_tests { value: ValueType::FuncForm( UserFn { arg_syms: vec!["input".to_string()], ast: Box::new(Seg::from( - Box::new(Ctr::Seg(Seg::from( - Box::from(Ctr::Symbol("input".to_string())), - Box::from(Ctr::None)))), - Box::new(Ctr::None), - )), + Box::from(Ctr::Symbol("input".to_string())), + Box::from(Ctr::None))), }), }; @@ -80,11 +100,8 @@ mod eval_tests { value: ValueType::FuncForm( UserFn { arg_syms: vec!["input".to_string()], ast: Box::new(Seg::from( - Box::new(Ctr::Seg(Seg::from( Box::from(Ctr::Symbol("input".to_string())), - Box::from(Ctr::None)))), - Box::new(Ctr::None), - )), + Box::from(Ctr::None))), }), }; diff --git a/tests/test_func.rs b/tests/test_func.rs index 6f18029..28a7027 100644 --- a/tests/test_func.rs +++ b/tests/test_func.rs @@ -45,7 +45,7 @@ mod func_tests { #[test] fn decl_and_call_external_func_singlet() { let mut syms = SymTable::new(); - match lex(&"((input))".to_string()) { + match lex(&"input".to_string()) { Err(e) => panic!("{}", e), Ok(finner) => { let test_external_func: Symbol = Symbol { @@ -85,7 +85,7 @@ mod func_tests { #[test] fn decl_and_call_external_func_multi_body() { let mut syms = SymTable::new(); - match lex(&"((input) (input))".to_string()) { + match lex(&"(input input)".to_string()) { Err(e) => panic!("{}", e), Ok(finner) => { let test_external_func: Symbol = Symbol{ @@ -106,7 +106,7 @@ mod func_tests { syms.insert(String::from("echo_2"), test_external_func); match syms.call_symbol(&"echo_2".to_string(), &args, true) { - Ok(ret) => assert_eq!(ret.to_string(), "(\"test\" \"test\")"), + Ok(ret) => assert_eq!(ret.to_string(), "'test'"), Err(e) => { print!("Call to function failed: {}\n", e); assert!(false); @@ -213,7 +213,7 @@ mod func_tests { #[test] fn too_many_args() { let mut syms = SymTable::new(); - match lex(&"((input))".to_string()) { + match lex(&"(input)".to_string()) { Err(e) => panic!("{}", e), Ok(finner) => { let test_external_func: Symbol = Symbol { @@ -246,7 +246,7 @@ mod func_tests { #[test] fn too_few_args() { let mut syms = SymTable::new(); - match lex(&"((input))".to_string()) { + match lex(&"(input)".to_string()) { Err(e) => panic!("{}", e), Ok(finner) => { let test_external_func: Symbol = Symbol { @@ -263,7 +263,7 @@ mod func_tests { syms.insert(String::from("test_func_in"), test_external_func); if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) { - assert_eq!(s, "failure to call echo: expected 1 args. Got 2."); + assert_eq!(s, "failure to call echo: expected 1 args. Got 0."); } else { print!("call to function succeeded (shouldnt have)"); assert!(false); @@ -298,7 +298,7 @@ mod func_tests { syms.insert(String::from("test_func_in"), test_internal_func); if let Err(s) = syms.call_symbol(&"test_func_in".to_string(), &args, true) { - assert_eq!(s, "failure to call echo: expected 1 args. Got 2."); + assert_eq!(s, "error in call to undefined-symbol: undefined symbol: undefined-symbol"); } else { print!("call to function succeeded (shouldnt have)"); assert!(false);