diff --git a/Readme.org b/Readme.org index 6e8e41e..c1cda85 100644 --- a/Readme.org +++ b/Readme.org @@ -148,8 +148,8 @@ Will need a concatenate function for tables *** TODO Main shell calls Load function on arg and exits *** TODO Can enter multiple lines of text, with formatting in repl *** TODO arithmetic operations -**** TODO typecast (int) -**** TODO typecast (float) +**** DONE typecast (int) +**** DONE typecast (float) **** DONE add **** DONE sub **** DONE div diff --git a/src/stl.rs b/src/stl.rs index 078900f..d0a7ff2 100644 --- a/src/stl.rs +++ b/src/stl.rs @@ -228,6 +228,28 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> { }, ); + syms.insert( + "int".to_string(), + Symbol { + name: String::from("int"), + args: Args::Lazy(1), + conditional_branches: false, + docs: math::INTCAST_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(math::intcast_callback)), + }, + ); + + syms.insert( + "float".to_string(), + Symbol { + name: String::from("float"), + args: Args::Lazy(1), + conditional_branches: false, + docs: math::FLOATCAST_DOCSTRING.to_string(), + value: ValueType::Internal(Rc::new(math::floatcast_callback)), + }, + ); + Ok(()) } diff --git a/src/stl/math.rs b/src/stl/math.rs index 1f1e8e2..c08cba0 100644 --- a/src/stl/math.rs +++ b/src/stl/math.rs @@ -125,3 +125,45 @@ pub fn mul_callback(ast: &Seg, _: &mut SymTable) -> Result { Ok(res) } } + +pub const INTCAST_DOCSTRING: &str = "takes a single arg and attempts to cast it to an Integer. +This will work for a float or a potentially a string. +If the cast to Integer fails, it will return Nothing and print an error. +Casting a float to an int will drop its decimal."; + +pub fn intcast_callback(ast: &Seg, _: &mut SymTable) -> Result { + // special case for float + if let Ctr::Float(f) = *ast.car { + Ok(Ctr::Integer(f as i128)) + } else if let Ctr::String(ref s) = *ast.car { + let int = str::parse::(s); + if int.is_err() { + Err(int.err().unwrap().to_string()) + } else { + Ok(Ctr::Integer(int.ok().unwrap())) + } + } else { + Err("int cast only takes a float or a string".to_string()) + } +} + +pub const FLOATCAST_DOCSTRING: &str = "takes a single arg and attempts to cast it to a float. +This will work for an integer or potentially a string. +If the cast to integer fails, this function will return nothing and print an error. +Casting an integer to a float can result in bad behaviour since float nodes are based on 64bit floats and int nodes are based on 128 bit integers."; + +pub fn floatcast_callback(ast: &Seg, _: &mut SymTable) -> Result { + // special case for float + if let Ctr::Integer(i) = *ast.car { + Ok(Ctr::Float(i as f64)) + } else if let Ctr::String(ref s) = *ast.car { + let int = str::parse::(&s); + if int.is_err() { + Err(int.err().unwrap().to_string()) + } else { + Ok(Ctr::Float(int.ok().unwrap())) + } + } else { + Err("float cast only takes an integer or a string".to_string()) + } +} diff --git a/tests/test_lib_math.rs b/tests/test_lib_math.rs index f208c7d..9709853 100644 --- a/tests/test_lib_math.rs +++ b/tests/test_lib_math.rs @@ -81,4 +81,68 @@ mod math_lib_tests { result.to_string(), ); } + + #[test] + fn test_float_to_int() { + let document = "(int 10.5)"; + let result = "10"; + + 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_string_to_int() { + let document = "(int '10')"; + let result = "10"; + + 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_int_to_float() { + let document = "(float 10)"; + let result = "10"; + + 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_string_to_float() { + let document = "(float '10.3')"; + let result = "10.3"; + + 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(), + ); + } }