Added LT, GT, LTE, and GTE functions, and big test coverage

This commit is contained in:
Ava Hahn 2023-03-07 22:01:01 -08:00
parent 5d89c6b684
commit c74d6f5ddf
Signed by untrusted user who does not match committer: affine
GPG key ID: 3A4645B8CF806069
6 changed files with 468 additions and 11 deletions

View file

@ -213,9 +213,9 @@ Will need a concatenate function for tables
***** DONE Test for Let Destructuring ***** DONE Test for Let Destructuring
**** TODO inc **** TODO inc
**** TODO dec **** TODO dec
**** TODO gt? **** DONE gt?
**** TODO lt? **** DONE lt?
**** TODO snippets for gte and lte **** DONE snippets for gte and lte
*** TODO string operations *** TODO string operations
**** TODO typecast (string) **** TODO typecast (string)
**** TODO contains **** TODO contains

View file

@ -16,7 +16,7 @@
*/ */
use std::fmt; use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::{Add, Sub, Mul, Div, Index}; use std::ops::{Add, Div, Index, Mul, Sub};
// Container // Container
#[derive(Debug, Default)] #[derive(Debug, Default)]
@ -321,7 +321,6 @@ impl Sub<Ctr> for Ctr {
} }
} }
impl Mul<Ctr> for Ctr { impl Mul<Ctr> for Ctr {
type Output = Ctr; type Output = Ctr;

View file

@ -291,7 +291,7 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
conditional_branches: false, conditional_branches: false,
docs: math::EXP_DOCSTRING.to_string(), docs: math::EXP_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(math::exp_callback)), value: ValueType::Internal(Rc::new(math::exp_callback)),
} },
); );
syms.insert( syms.insert(
@ -302,7 +302,51 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
conditional_branches: false, conditional_branches: false,
docs: math::MOD_DOCSTRING.to_string(), docs: math::MOD_DOCSTRING.to_string(),
value: ValueType::Internal(Rc::new(math::mod_callback)), 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(()) Ok(())

View file

@ -264,3 +264,97 @@ pub fn mod_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
Ok(Ctr::Seg(ret)) 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<Ctr, String> {
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<Ctr, String> {
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<Ctr, String> {
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<Ctr, String> {
if let Ctr::Bool(b) = isgt_callback(ast, syms)? {
Ok(Ctr::Bool(!b))
} else {
Err("impossible state: islt returned non-bool".to_string())
}
}

View file

@ -145,7 +145,7 @@ impl Args {
} else { } else {
return Err("expected no args".to_string()); return Err("expected no args".to_string());
} }
}, }
Args::Infinite => { Args::Infinite => {
if !args.is_empty() { if !args.is_empty() {
@ -153,7 +153,7 @@ impl Args {
} else { } else {
return Err("expected args but none were provided".to_string()); return Err("expected args but none were provided".to_string());
} }
}, }
Args::Lazy(ref num) => { Args::Lazy(ref num) => {
let called_arg_count = args.len(); let called_arg_count = args.len();
@ -168,7 +168,7 @@ impl Args {
} else if let Ctr::None = *args.car { } else if let Ctr::None = *args.car {
return Err(format!("expected {} args. Got 0.", num,)); return Err(format!("expected {} args. Got 0.", num,));
} }
}, }
Args::Strict(ref arg_types) => { Args::Strict(ref arg_types) => {
let mut idx: usize = 0; let mut idx: usize = 0;
@ -203,7 +203,7 @@ impl Args {
return Err("too few arguments".to_string()); return Err("too few arguments".to_string());
} }
} }
}, }
} }
Ok(()) Ok(())

View file

@ -288,4 +288,324 @@ mod math_lib_tests {
result1.to_string(), 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(),
);
}
} }