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 error::{self, Error};
|
||||||
use value::Value;
|
use value::Value;
|
||||||
|
|
||||||
|
pub mod builtin;
|
||||||
|
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
argument_amount: Option<usize>,
|
argument_amount: Option<usize>,
|
||||||
function: Box<Fn(&[Value]) -> Result<Value, Error>>,
|
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)])));
|
//! 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
|
//! ### Values
|
||||||
//!
|
//!
|
||||||
//! Operators take values as arguments and produce values as results.
|
//! Operators take values as arguments and produce values as results.
|
||||||
@ -152,7 +164,7 @@
|
|||||||
//!
|
//!
|
||||||
//! Variables have a precedence of 200.
|
//! Variables have a precedence of 200.
|
||||||
//!
|
//!
|
||||||
//! ### Functions
|
//! ### User-Defined Functions
|
||||||
//!
|
//!
|
||||||
//! This crate also allows to define arbitrary functions to be used in parsed expressions.
|
//! This crate also allows to define arbitrary functions to be used in parsed expressions.
|
||||||
//! A function is defined as a `Function` instance.
|
//! A function is defined as a `Function` instance.
|
||||||
@ -504,6 +516,15 @@ mod test {
|
|||||||
eval_with_configuration("count 5", &configuration),
|
eval_with_configuration("count 5", &configuration),
|
||||||
Ok(Value::Int(1))
|
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]
|
#[test]
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::{configuration::Configuration, error::*, value::Value};
|
use crate::{configuration::Configuration, error::*, value::Value};
|
||||||
|
use function::builtin::builtin_function;
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
@ -687,6 +688,8 @@ impl Operator for FunctionIdentifier {
|
|||||||
|
|
||||||
if let Some(function) = configuration.get_function(&self.identifier) {
|
if let Some(function) = configuration.get_function(&self.identifier) {
|
||||||
function.call(arguments)
|
function.call(arguments)
|
||||||
|
} else if let Some(builtin_function) = builtin_function(&self.identifier) {
|
||||||
|
builtin_function.call(arguments)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::FunctionIdentifierNotFound(self.identifier.clone()))
|
Err(Error::FunctionIdentifierNotFound(self.identifier.clone()))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user