Implement min and max builtin functions
Implement #8, partially implement #1
This commit is contained in:
parent
4c6c46f9d8
commit
92da684c69
58
src/function/builtin.rs
Normal file
58
src/function/builtin.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use value::{FloatType, IntType};
|
||||
use Error;
|
||||
use Function;
|
||||
use Value;
|
||||
|
||||
pub fn builtin_function(identifier: &str) -> Option<Function> {
|
||||
match identifier {
|
||||
"min" => Some(Function::new(
|
||||
None,
|
||||
Box::new(|arguments| {
|
||||
let mut min_int = IntType::max_value();
|
||||
let mut min_float = 1.0f64 / 0.0f64;
|
||||
debug_assert!(min_float.is_infinite());
|
||||
|
||||
for argument in arguments {
|
||||
if let Value::Float(float) = argument {
|
||||
min_float = min_float.min(*float);
|
||||
} else if let Value::Int(int) = argument {
|
||||
min_int = min_int.min(*int);
|
||||
} else {
|
||||
return Err(Error::expected_number(argument.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
if (min_int as FloatType) < min_float {
|
||||
Ok(Value::Int(min_int))
|
||||
} else {
|
||||
Ok(Value::Float(min_float))
|
||||
}
|
||||
}),
|
||||
)),
|
||||
"max" => Some(Function::new(
|
||||
None,
|
||||
Box::new(|arguments| {
|
||||
let mut max_int = IntType::min_value();
|
||||
let mut max_float = -1.0f64 / 0.0f64;
|
||||
debug_assert!(max_float.is_infinite());
|
||||
|
||||
for argument in arguments {
|
||||
if let Value::Float(float) = argument {
|
||||
max_float = max_float.max(*float);
|
||||
} else if let Value::Int(int) = argument {
|
||||
max_int = max_int.max(*int);
|
||||
} else {
|
||||
return Err(Error::expected_number(argument.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
if (max_int as FloatType) > max_float {
|
||||
Ok(Value::Int(max_int))
|
||||
} else {
|
||||
Ok(Value::Float(max_float))
|
||||
}
|
||||
}),
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
use error::{self, Error};
|
||||
use value::Value;
|
||||
|
||||
pub mod builtin;
|
||||
|
||||
pub struct Function {
|
||||
argument_amount: Option<usize>,
|
||||
function: Box<Fn(&[Value]) -> Result<Value, Error>>,
|
||||
|
23
src/lib.rs
23
src/lib.rs
@ -116,6 +116,18 @@
|
||||
//! assert_eq!(eval("1, 2, 3"), Ok(Value::from(vec![Value::from(1), Value::from(2), Value::from(3)])));
|
||||
//! ```
|
||||
//!
|
||||
//! ### Builtin Functions
|
||||
//!
|
||||
//! This crate offers a set of builtin functions.
|
||||
//!
|
||||
//! | Identifier | Argument Amount | Description |
|
||||
//! |------------|-----------------|-------------|
|
||||
//! | min | >= 1 | Returns the minimum of the arguments |
|
||||
//! | max | >= 1 | Returns the maximum of the arguments |
|
||||
//!
|
||||
//! The `min` and `max` functions can deal with a mixture of integer and floating point arguments.
|
||||
//! They return the result as the type it was passed into the function.
|
||||
//!
|
||||
//! ### Values
|
||||
//!
|
||||
//! Operators take values as arguments and produce values as results.
|
||||
@ -152,7 +164,7 @@
|
||||
//!
|
||||
//! Variables have a precedence of 200.
|
||||
//!
|
||||
//! ### Functions
|
||||
//! ### User-Defined Functions
|
||||
//!
|
||||
//! This crate also allows to define arbitrary functions to be used in parsed expressions.
|
||||
//! A function is defined as a `Function` instance.
|
||||
@ -504,6 +516,15 @@ mod test {
|
||||
eval_with_configuration("count 5", &configuration),
|
||||
Ok(Value::Int(1))
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
eval_with_configuration("min(4.0, 3)", &configuration),
|
||||
Ok(Value::Int(3))
|
||||
);
|
||||
assert_eq!(
|
||||
eval_with_configuration("max(4.0, 3)", &configuration),
|
||||
Ok(Value::Float(4.0))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::{configuration::Configuration, error::*, value::Value};
|
||||
use function::builtin::builtin_function;
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
mod display;
|
||||
@ -687,6 +688,8 @@ impl Operator for FunctionIdentifier {
|
||||
|
||||
if let Some(function) = configuration.get_function(&self.identifier) {
|
||||
function.call(arguments)
|
||||
} else if let Some(builtin_function) = builtin_function(&self.identifier) {
|
||||
builtin_function.call(arguments)
|
||||
} else {
|
||||
Err(Error::FunctionIdentifierNotFound(self.identifier.clone()))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user