use std::collections::HashMap;
use crate::{
create_func, decl_func, function::Function, function::*, out::ErrorType, read_vec_values,
value::Value, EvalResult, ValueType,
};
use lazy_static::*;
use num::complex::ComplexFloat;
use rand::Rng;
use std::sync::RwLock;
use tuple_conv::RepeatedTuple;
lazy_static! {
#[derive(Debug, Clone)]
static ref CONSTANTS: RwLock<HashMap<&'static str, Value>> = RwLock::new
({
let mut m = HashMap::new();
use std::f64::consts;
m.insert("pi", Value::Float(consts::PI));
m.insert("e", Value::Float(consts::E));
m.insert("tau", Value::Float(consts::TAU));
m.insert("phi", Value::Float(1.618_033_988_749_894));
m.insert("true", Value::Bool(true));
m.insert("false", Value::Bool(false));
m.insert("i", Value::Complex(num::Complex::i()));
m
});
#[derive(Debug, Clone)]
static ref BUILT_IN_FUNCTIONS: RwLock<Vec<Function>> = RwLock::new(vec![
create_func!(min, Arguments::Dynamic),
create_func!(max, Arguments::Dynamic),
create_func!(floor, Arguments::Const(1)),
create_func!(ceil, Arguments::Const(1)),
create_func!(round, Arguments::Const(1)),
create_func!(abs, Arguments::Const(1)),
create_func!(sqrt, Arguments::Const(1)),
create_func!(ln, Arguments::Const(1)),
create_func!(log, Arguments::Const(2)),
create_func!(exp, Arguments::Const(1)),
create_func!(rand, Arguments::Const(2)),
create_func!(branch, Arguments::Const(3)),
create_func!(sin, Arguments::Const(1)),
create_func!(cos, Arguments::Const(1)),
create_func!(tan, Arguments::Const(1)),
create_func!(asin, Arguments::Const(1)),
create_func!(acos, Arguments::Const(1)),
create_func!(atan, Arguments::Const(1)),
create_func!(sinh, Arguments::Const(1)),
create_func!(cosh, Arguments::Const(1)),
create_func!(tanh, Arguments::Const(1)),
create_func!(asinh, Arguments::Const(1)),
create_func!(acosh, Arguments::Const(1)),
create_func!(atanh, Arguments::Const(1)),
create_func!(re, Arguments::Const(1)),
create_func!(im, Arguments::Const(1)),
create_func!(polar, Arguments::Const(1)),
create_func!(arg, Arguments::Const(1)),
create_func!(norm, Arguments::Const(1)),
]);
}
pub fn get_built_in_function(identifier: &str) -> Option<Function> {
get_built_in_functions_vec()
.iter()
.find(|x| x.func_identifier == identifier)
.cloned()
}
pub fn get_built_in_const(identifier: &str) -> Option<Value> {
get_built_in_consts_map()
.iter()
.find(|&x| x.0 == identifier)
.map(|x| x.1.clone())
}
pub fn reserved_keywords<'a>() -> Vec<&'a str> {
[
get_built_in_consts_map()
.iter()
.map(|x| x.0)
.collect::<Vec<&str>>(),
get_built_in_functions_vec()
.iter()
.map(|x| x.func_identifier)
.collect::<Vec<&str>>(),
]
.concat()
}
pub fn get_built_in_functions_vec() -> Vec<Function> {
BUILT_IN_FUNCTIONS.read().unwrap().iter().cloned().collect()
}
pub fn get_built_in_consts_map() -> Vec<(&'static str, Value)> {
CONSTANTS
.read()
.unwrap()
.iter()
.map(|x| (x.0.clone(), x.1.clone()))
.collect()
}
pub fn add_built_in_function(func: Function) {
BUILT_IN_FUNCTIONS.write().unwrap().push(func)
}
pub fn add_built_in_const(identifier: &'static str, value: Value) -> Option<Value> {
CONSTANTS.write().unwrap().insert(identifier, value)
}
pub fn remove_built_in_function(func_identifier: &str) -> Option<Function> {
if let Some(index) = BUILT_IN_FUNCTIONS
.read()
.unwrap()
.iter()
.position(|x| x.func_identifier == func_identifier)
{
Some(BUILT_IN_FUNCTIONS.write().unwrap().swap_remove(index))
} else {
None
}
}
pub fn remove_built_in_const(const_identifier: &str) -> Option<Value> {
CONSTANTS.write().unwrap().remove(const_identifier)
}
decl_func!(
min,
FunctionType::Std,
|v| {
let vec = v.as_vector();
let mut min = vec[0].as_float()?;
for elem in vec {
if elem.as_float()? < min {
min = elem.as_float()?;
}
}
Ok(Value::Float(min))
},
ValueType::VectorType
);
decl_func!(
max,
FunctionType::Std,
|v| {
let vec = v.as_vector();
let mut max = vec[0].as_float()?;
for elem in vec {
if elem.as_float()? > max {
max = elem.as_float()?;
}
}
Ok(Value::Float(max))
},
ValueType::VectorType
);
decl_func!(
floor,
FunctionType::Std,
|v| Ok(v.as_float()?.floor()),
ValueType::FloatType
);
decl_func!(
ceil,
FunctionType::Std,
|v| Ok(v.as_float()?.ceil()),
ValueType::FloatType
);
decl_func!(
round,
FunctionType::Std,
|v| Ok(v.as_float()?.round()),
ValueType::FloatType
);
decl_func!(
abs,
FunctionType::Std,
|v: Value| Ok(Value::Float(v.as_complex()?.abs())),
ValueType::ComplexType
);
decl_func!(
sqrt,
FunctionType::Std,
|v: Value| Ok(Value::Complex(v.as_complex()?.sqrt())),
ValueType::ComplexType
);
decl_func!(
ln,
FunctionType::Std,
|v| Ok(v.as_complex()?.ln()),
ValueType::ComplexType
);
decl_func!(
log,
FunctionType::Std,
|v| {
read_vec_values!(v, base, argument);
Ok(argument.as_complex()?.log(base.as_float()?))
},
ValueType::VectorType
);
decl_func!(
exp,
FunctionType::Std,
|v| Ok(v.as_complex()?.exp()),
ValueType::ComplexType
);
decl_func!(
rand,
FunctionType::Std,
|v| {
read_vec_values!(v, min, max);
Ok(Value::Float(
rand::thread_rng().gen_range(min.as_float()?..max.as_float()?),
))
},
ValueType::VectorType
);
fn branch(arguments: &Vec<Box<Expression>>, context: &Context, depth: u32) -> EvalResult<Value> {
let condition = arguments[0].eval(context, None, depth)?.as_bool()?;
if condition {
Ok(arguments[1].eval(context, None, depth)?)
} else {
Ok(arguments[2].eval(context, None, depth)?)
}
}
decl_func!(
sin,
FunctionType::Trig,
|v| Ok(v.as_complex()?.sin()),
ValueType::ComplexType
);
decl_func!(
cos,
FunctionType::Trig,
|v| Ok(v.as_complex()?.cos()),
ValueType::ComplexType
);
decl_func!(
tan,
FunctionType::Trig,
|v| Ok(v.as_complex()?.tan()),
ValueType::ComplexType
);
decl_func!(
asin,
FunctionType::InverseTrig,
|v| Ok(v.as_complex()?.asin()),
ValueType::ComplexType
);
decl_func!(
acos,
FunctionType::InverseTrig,
|v| Ok(v.as_complex()?.acos()),
ValueType::ComplexType
);
decl_func!(
atan,
FunctionType::InverseTrig,
|v| Ok(v.as_complex()?.atan()),
ValueType::ComplexType
);
decl_func!(
sinh,
FunctionType::Trig,
|v| Ok(v.as_complex()?.sinh()),
ValueType::ComplexType
);
decl_func!(
cosh,
FunctionType::Trig,
|v| Ok(v.as_complex()?.cosh()),
ValueType::ComplexType
);
decl_func!(
tanh,
FunctionType::Trig,
|v| Ok(v.as_complex()?.tanh()),
ValueType::ComplexType
);
decl_func!(
asinh,
FunctionType::InverseTrig,
|v| Ok(v.as_complex()?.asinh()),
ValueType::ComplexType
);
decl_func!(
acosh,
FunctionType::InverseTrig,
|v| Ok(v.as_complex()?.acosh()),
ValueType::ComplexType
);
decl_func!(
atanh,
FunctionType::InverseTrig,
|v| Ok(v.as_complex()?.atanh()),
ValueType::ComplexType
);
decl_func!(
re,
FunctionType::Std,
|v| Ok(v.as_complex()?.re),
ValueType::ComplexType
);
decl_func!(
im,
FunctionType::Std,
|v| Ok(v.as_complex()?.im),
ValueType::ComplexType
);
decl_func!(
polar,
FunctionType::Std,
|v| Ok(v.as_complex()?.to_polar().to_vec()),
ValueType::ComplexType
);
decl_func!(
arg,
FunctionType::Std,
|v| Ok(v.as_complex()?.arg()),
ValueType::ComplexType
);
decl_func!(
norm,
FunctionType::Std,
|v| Ok(v.as_complex()?.norm()),
ValueType::ComplexType
);