add mod and exp functions, tests, and also some snippets for common

patterns in the readme
This commit is contained in:
Ava Hahn 2023-03-07 21:27:45 -08:00
parent 7fd47c1812
commit 0c5d14ed8e
Signed by untrusted user who does not match committer: affine
GPG key ID: 3A4645B8CF806069
4 changed files with 323 additions and 13 deletions

View file

@ -167,3 +167,99 @@ pub fn floatcast_callback(ast: &Seg, _: &mut SymTable) -> Result<Ctr, String> {
Err("float cast only takes an integer or a string".to_string())
}
}
pub const EXP_DOCSTRING: &str = "Takes two args, both expected to be numeric.
Returns the first arg to the power of the second arg.
Does not handle overflow or underflow.
PANIC CASES:
- arg1 is a float and arg2 is greater than an int32
- an integer exceeding the size of a float64 is raised to a float power
- an integer is rased to the power of another integer exceeding the max size of an unsigned 32bit integer";
pub fn exp_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::Float(f64::powf(lf, rf))),
Ctr::Integer(ri) => Ok(Ctr::Float(f64::powi(lf, ri as i32))),
_ => Err("exp not implemented for these arguments".to_string()),
},
Ctr::Integer(li) => match second {
Ctr::Float(rf) => Ok(Ctr::Float(f64::powf(li as f64, rf))),
Ctr::Integer(ri) => Ok(Ctr::Integer(li.pow(ri as u32))),
_ => Err("exp not implemented for these arguments".to_string()),
},
_ => Err("exp not implemented for these arguments".to_string()),
}
}
pub const MOD_DOCSTRING: &str = "Takes two args, both expected to be numeric.
Returns a list of two values: the modulus and the remainder.
Example: (mod 5 3) -> (1 2)
PANIC CASES:
- A float is modulo an integer larger than a max f64
- An integer larger than a max f64 is modulo a float
";
pub fn mod_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());
}
let mut ret = Seg::new();
match first {
Ctr::Float(lf) => match second {
Ctr::Float(rf) => {
ret.append(Box::new(Ctr::Integer((lf / rf) as i128)));
ret.append(Box::new(Ctr::Integer((lf % rf) as i128)));
},
Ctr::Integer(ri) => {
ret.append(Box::new(Ctr::Integer((lf / ri as f64) as i128)));
ret.append(Box::new(Ctr::Integer((lf % ri as f64) as i128)));
},
_ => return Err("mod not implemented for these arguments".to_string()),
},
Ctr::Integer(li) => match second {
Ctr::Float(rf) => {
ret.append(Box::new(Ctr::Integer((li as f64 / rf) as i128)));
ret.append(Box::new(Ctr::Integer((li as f64 % rf) as i128))); },
Ctr::Integer(ri) => {
ret.append(Box::new(Ctr::Integer(li / ri)));
ret.append(Box::new(Ctr::Integer(li % ri)));
},
_ => return Err("mod not implemented for these arguments".to_string()),
},
_ => return Err("mod not implemented for these arguments".to_string()),
}
Ok(Ctr::Seg(ret))
}