From c74d6f5ddf15346dd8a9fa023b8c7fe5a3c23fe1 Mon Sep 17 00:00:00 2001 From: Ava Hahn Date: Tue, 7 Mar 2023 22:01:01 -0800 Subject: [PATCH] Added LT, GT, LTE, and GTE functions, and big test coverage --- Readme.org | 6 +- src/segment.rs | 3 +- src/stl.rs | 48 ++++++- src/stl/math.rs | 94 ++++++++++++ src/sym.rs | 8 +- tests/test_lib_math.rs | 320 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 468 insertions(+), 11 deletions(-) diff --git a/Readme.org b/Readme.org index aa0c0a6..c3af010 100644 --- a/Readme.org +++ b/Readme.org @@ -213,9 +213,9 @@ Will need a concatenate function for tables ***** DONE Test for Let Destructuring **** TODO inc **** TODO dec -**** TODO gt? -**** TODO lt? -**** TODO snippets for gte and lte +**** DONE gt? +**** DONE lt? +**** DONE snippets for gte and lte *** TODO string operations **** TODO typecast (string) **** TODO contains diff --git a/src/segment.rs b/src/segment.rs index 1620fb3..31cdbe8 100644 --- a/src/segment.rs +++ b/src/segment.rs @@ -16,7 +16,7 @@ */ use std::fmt; use std::marker::PhantomData; -use std::ops::{Add, Sub, Mul, Div, Index}; +use std::ops::{Add, Div, Index, Mul, Sub}; // Container #[derive(Debug, Default)] @@ -321,7 +321,6 @@ impl Sub for Ctr { } } - impl Mul for Ctr { type Output = Ctr; diff --git a/src/stl.rs b/src/stl.rs index fd506fb..ccf6033 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -291,7 +291,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::EXP_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::exp_callback)), - } + }, ); syms.insert( @@ -302,7 +302,51 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { conditional_branches: false, docs: math::MOD_DOCSTRING.to_string(), value: ValueType::Internal(Rc::new(math::mod_callback)), - } + }, + ); + + syms.insert( + "gt?".to_string(), + Symbol { + name: String::from("gt?"), + args: Args::Lazy(2), + conditional_branches: false, + docs: math::ISGT_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(math::isgt_callback)), + }, + ); + + syms.insert( + "lt?".to_string(), + Symbol { + name: String::from("lt?"), + args: Args::Lazy(2), + conditional_branches: false, + docs: math::ISLT_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(math::islt_callback)), + }, + ); + + syms.insert( + "gte?".to_string(), + Symbol { + name: String::from("gt?"), + args: Args::Lazy(2), + conditional_branches: false, + docs: math::ISGTE_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(math::isgte_callback)), + }, + ); + + syms.insert( + "lte?".to_string(), + Symbol { + name: String::from("lt?"), + args: Args::Lazy(2), + conditional_branches: false, + docs: math::ISLTE_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(math::islte_callback)), + }, ); Ok(()) diff --git a/src/stl/math.rs b/src/stl/math.rs index c1c3e44..41a9953 100644 --- a/src/stl/math.rs +++ b/src/stl/math.rs @@ -264,3 +264,97 @@ pub fn mod_callback(ast: &Seg, _: &mut SymTable) -> Result { Ok(Ctr::Seg(ret)) } + +pub const ISGT_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float. +Returns true or false according to whether the first argument is bigger than the second argument. +May panic if an integer larger than a max f64 is compared to a float."; + +pub fn isgt_callback(ast: &Seg, _: &mut SymTable) -> Result { + let first = *ast.car.clone(); + if !isnumeric(&first) { + return Err("first argument must be numeric".to_string()); + } + let second: Ctr; + if let Ctr::Seg(ref s) = *ast.cdr { + second = *s.car.clone(); + } else { + return Err("impossible error: needs two arguments".to_string()); + } + if !isnumeric(&second) { + return Err("second argument must be numeric".to_string()); + } + + match first { + Ctr::Float(lf) => match second { + Ctr::Float(rf) => Ok(Ctr::Bool(lf > rf)), + Ctr::Integer(ri) => Ok(Ctr::Bool(lf > ri as f64)), + _ => Err("gt? not implemented for these arguments".to_string()), + }, + Ctr::Integer(li) => match second { + Ctr::Float(rf) => Ok(Ctr::Bool(li as f64 > rf)), + Ctr::Integer(ri) => Ok(Ctr::Bool(li > ri)), + _ => Err("gt? not implemented for these arguments".to_string()), + }, + + _ => Err("gt? not implemented for these arguments".to_string()), + } +} + +pub const ISLT_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float. +Returns true or false according to whether the first argument is smaller than the second argument. +May panic if an integer larger than a max f64 is compared to a float."; + +pub fn islt_callback(ast: &Seg, _: &mut SymTable) -> Result { + let first = *ast.car.clone(); + if !isnumeric(&first) { + return Err("first argument must be numeric".to_string()); + } + let second: Ctr; + if let Ctr::Seg(ref s) = *ast.cdr { + second = *s.car.clone(); + } else { + return Err("impossible error: needs two arguments".to_string()); + } + if !isnumeric(&second) { + return Err("second argument must be numeric".to_string()); + } + + match first { + Ctr::Float(lf) => match second { + Ctr::Float(rf) => Ok(Ctr::Bool(lf < rf)), + Ctr::Integer(ri) => Ok(Ctr::Bool(lf < ri as f64)), + _ => Err("gt? not implemented for these arguments".to_string()), + }, + Ctr::Integer(li) => match second { + Ctr::Float(rf) => Ok(Ctr::Bool((li as f64) < rf)), + Ctr::Integer(ri) => Ok(Ctr::Bool(li < ri)), + _ => Err("gt? not implemented for these arguments".to_string()), + }, + + _ => Err("gt? not implemented for these arguments".to_string()), + } +} + +pub const ISGTE_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float. +Returns true or false according to whether the first argument is greater than or equal to the second argument. +May panic if an integer larger than a max f64 is compared to a float."; + +pub fn isgte_callback(ast: &Seg, syms: &mut SymTable) -> Result { + if let Ctr::Bool(b) = islt_callback(ast, syms)? { + Ok(Ctr::Bool(!b)) + } else { + Err("impossible state: islt returned non-bool".to_string()) + } +} + +pub const ISLTE_DOCSTRING: &str = "takes two args, which must both evaluate to an Integer or Float. +Returns true or false according to whether the first argument is less than or equal to the second argument. +May panic if an integer larger than a max f64 is compared to a float."; + +pub fn islte_callback(ast: &Seg, syms: &mut SymTable) -> Result { + if let Ctr::Bool(b) = isgt_callback(ast, syms)? { + Ok(Ctr::Bool(!b)) + } else { + Err("impossible state: islt returned non-bool".to_string()) + } +} diff --git a/src/sym.rs b/src/sym.rs index 344715e..6f5470d 100644 --- a/src/sym.rs +++ b/src/sym.rs @@ -145,7 +145,7 @@ impl Args { } else { return Err("expected no args".to_string()); } - }, + } Args::Infinite => { if !args.is_empty() { @@ -153,7 +153,7 @@ impl Args { } else { return Err("expected args but none were provided".to_string()); } - }, + } Args::Lazy(ref num) => { let called_arg_count = args.len(); @@ -168,7 +168,7 @@ impl Args { } else if let Ctr::None = *args.car { return Err(format!("expected {} args. Got 0.", num,)); } - }, + } Args::Strict(ref arg_types) => { let mut idx: usize = 0; @@ -203,7 +203,7 @@ impl Args { return Err("too few arguments".to_string()); } } - }, + } } Ok(()) diff --git a/tests/test_lib_math.rs b/tests/test_lib_math.rs index 98b0963..deb656e 100644 --- a/tests/test_lib_math.rs +++ b/tests/test_lib_math.rs @@ -288,4 +288,324 @@ mod math_lib_tests { result1.to_string(), ); } + + #[test] + fn test_ii_gt_t() { + let document = "(gt? 4 3)"; + let result = true; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_ii_gt_f() { + let document = "(gt? 2 3)"; + let result = false; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_if_gt_t() { + let document = "(gt? 4 3.1)"; + let result = true; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_if_gt_f() { + let document = "(gt? 3 3.1)"; + let result = false; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_fi_gt_t() { + let document = "(gt? 4.1 4)"; + let result = true; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_fi_gt_f() { + let document = "(gt? 2.1 3)"; + let result = false; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_ff_gt_t() { + let document = "(gt? 3.2 3.1)"; + let result = true; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_ff_gt_f() { + let document = "(gt? 3.1 3.2)"; + let result = false; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_ii_lt_f() { + let document = "(lt? 4 3)"; + let result = false; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_ii_lt_t() { + let document = "(lt? 2 3)"; + let result = true; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_if_lt_f() { + let document = "(lt? 4 3.1)"; + let result = false; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_if_lt_t() { + let document = "(lt? 3 3.1)"; + let result = true; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_fi_lt_f() { + let document = "(lt? 4.1 4)"; + let result = false; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_fi_lt_t() { + let document = "(lt? 2.1 3)"; + let result = true; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_ff_lt_f() { + let document = "(lt? 3.2 3.1)"; + let result = false; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_ff_lt_ft() { + let document = "(lt? 3.1 3.2)"; + let result = true; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_lte() { + let document = "(lte? 3.2 3.1)"; + let result = false; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_lte_e() { + let document = "(lte? 3.2 3.2)"; + let result = true; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_gte() { + let document = "(gte? 3.1 3.2)"; + let result = false; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } + + #[test] + fn test_gte_e() { + let document = "(gte? 3.1 3.1)"; + let result = true; + + let mut syms = SymTable::new(); + static_stdlib(&mut syms).unwrap(); + dynamic_stdlib(&mut syms).unwrap(); + assert_eq!( + *eval(&lex(&document.to_string()).unwrap(), &mut syms) + .unwrap() + .to_string(), + result.to_string(), + ); + } }