use crate::eval::coercion::to_number;
use crate::eval::functions::check_arity;
use crate::types::{ErrorKind, Value};
pub fn pi_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 0, 0) {
return err;
}
Value::Number(std::f64::consts::PI)
}
pub fn sin_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let result = libm::sin(n);
if !result.is_finite() {
return Value::Error(ErrorKind::Num);
}
Value::Number(result)
}
pub fn cos_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let result = libm::cos(n);
if !result.is_finite() {
return Value::Error(ErrorKind::Num);
}
Value::Number(result)
}
pub fn tan_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let result = libm::tan(n);
if !result.is_finite() {
return Value::Error(ErrorKind::Num);
}
Value::Number(result)
}
pub fn acos_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let result = libm::acos(n);
if result.is_nan() {
return Value::Error(ErrorKind::Num);
}
Value::Number(result)
}
pub fn asin_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let result = libm::asin(n);
if result.is_nan() {
return Value::Error(ErrorKind::Num);
}
Value::Number(result)
}
pub fn atan_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
Value::Number(libm::atan(n))
}
pub fn atan2_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 2, 2) {
return err;
}
let n_x = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let n_y = match to_number(args[1].clone()) {
Err(e) => return e,
Ok(v) => v,
};
if n_x == 0.0 && n_y == 0.0 {
return Value::Error(ErrorKind::DivByZero);
}
Value::Number(libm::atan2(n_y, n_x))
}
pub fn degrees_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
Value::Number(n * 180.0 / std::f64::consts::PI)
}
pub fn radians_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
Value::Number(n * std::f64::consts::PI / 180.0)
}
pub fn sinh_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
if n.abs() >= 710.0 {
return Value::Error(ErrorKind::Num);
}
let result = libm::sinh(n);
if !result.is_finite() {
return Value::Error(ErrorKind::Num);
}
Value::Number(result)
}
pub fn cosh_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let result = libm::cosh(n);
if !result.is_finite() || result > 9.99e307 {
return Value::Error(ErrorKind::Num);
}
Value::Number(result)
}
pub fn tanh_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
Value::Number(libm::tanh(n))
}
pub fn acosh_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let result = libm::acosh(n);
if result.is_nan() {
return Value::Error(ErrorKind::Num);
}
Value::Number(result)
}
pub fn asinh_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
Value::Number(libm::asinh(n))
}
pub fn atanh_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let result = libm::atanh(n);
if !result.is_finite() || result.is_nan() {
return Value::Error(ErrorKind::Num);
}
Value::Number(result)
}
pub fn cot_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let tan = libm::tan(n);
if tan == 0.0 || !tan.is_finite() {
return Value::Error(ErrorKind::DivByZero);
}
Value::Number(1.0 / tan)
}
pub fn coth_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
if n == 0.0 {
return Value::Error(ErrorKind::DivByZero);
}
let tanh = libm::tanh(n);
if tanh == 0.0 || !tanh.is_finite() {
return Value::Error(ErrorKind::DivByZero);
}
Value::Number(1.0 / tanh)
}
pub fn csc_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
if n.abs() >= 1e14 {
return Value::Error(ErrorKind::Num);
}
let sin = libm::sin(n);
if sin == 0.0 || !sin.is_finite() {
return Value::Error(ErrorKind::DivByZero);
}
Value::Number(1.0 / sin)
}
pub fn csch_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
if n == 0.0 {
return Value::Error(ErrorKind::DivByZero);
}
let sinh = libm::sinh(n);
if !sinh.is_finite() {
return Value::Error(ErrorKind::Num);
}
if sinh == 0.0 {
return Value::Error(ErrorKind::DivByZero);
}
Value::Number(1.0 / sinh)
}
pub fn sec_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let cos = libm::cos(n);
if cos == 0.0 || !cos.is_finite() {
return Value::Error(ErrorKind::DivByZero);
}
Value::Number(1.0 / cos)
}
pub fn sech_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
let cosh = libm::cosh(n);
if !cosh.is_finite() {
return Value::Error(ErrorKind::Num);
}
Value::Number(1.0 / cosh)
}
pub fn acot_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
Value::Number(libm::atan(1.0 / n))
}
pub fn acoth_fn(args: &[Value]) -> Value {
if let Some(err) = check_arity(args, 1, 1) {
return err;
}
let n = match to_number(args[0].clone()) {
Err(e) => return e,
Ok(v) => v,
};
if n.abs() <= 1.0 {
return Value::Error(ErrorKind::Num);
}
let result = libm::atanh(1.0 / n);
if !result.is_finite() || result.is_nan() {
return Value::Error(ErrorKind::Num);
}
Value::Number(result)
}
#[cfg(test)]
mod tests;