add mod and exp functions, tests, and also some snippets for common
patterns in the readme
This commit is contained in:
parent
7fd47c1812
commit
0c5d14ed8e
4 changed files with 323 additions and 13 deletions
22
src/stl.rs
22
src/stl.rs
|
|
@ -283,6 +283,28 @@ pub fn static_stdlib(syms: &mut SymTable) -> Result<(), String> {
|
|||
},
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"exp".to_string(),
|
||||
Symbol {
|
||||
name: String::from("exp"),
|
||||
args: Args::Lazy(2),
|
||||
conditional_branches: false,
|
||||
docs: math::EXP_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::exp_callback)),
|
||||
}
|
||||
);
|
||||
|
||||
syms.insert(
|
||||
"mod".to_string(),
|
||||
Symbol {
|
||||
name: String::from("mod"),
|
||||
args: Args::Lazy(2),
|
||||
conditional_branches: false,
|
||||
docs: math::MOD_DOCSTRING.to_string(),
|
||||
value: ValueType::Internal(Rc::new(math::mod_callback)),
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue