Implement min and max builtin functions

Implement #8, partially implement #1
This commit is contained in:
Sebastian Schmidt 2019-03-19 20:08:23 +02:00
parent 4c6c46f9d8
commit 92da684c69
4 changed files with 85 additions and 1 deletions

58
src/function/builtin.rs Normal file
View 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,
}
}

View File

@ -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>>,

View File

@ -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]

View File

@ -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()))
}