Format code
This commit is contained in:
parent
6f533ca925
commit
502ec0adce
@ -9,114 +9,98 @@ use Value;
|
|||||||
|
|
||||||
pub fn builtin_function(identifier: &str) -> Option<Function> {
|
pub fn builtin_function(identifier: &str) -> Option<Function> {
|
||||||
match identifier {
|
match identifier {
|
||||||
"min" => Some(Function::new(
|
"min" => Some(Function::new(Box::new(|argument| {
|
||||||
Box::new(|argument| {
|
let arguments = expect_tuple(argument)?;
|
||||||
let arguments = expect_tuple(argument)?;
|
let mut min_int = IntType::max_value();
|
||||||
let mut min_int = IntType::max_value();
|
let mut min_float = 1.0f64 / 0.0f64;
|
||||||
let mut min_float = 1.0f64 / 0.0f64;
|
debug_assert!(min_float.is_infinite());
|
||||||
debug_assert!(min_float.is_infinite());
|
|
||||||
|
|
||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
if let Value::Float(float) = argument {
|
if let Value::Float(float) = argument {
|
||||||
min_float = min_float.min(*float);
|
min_float = min_float.min(*float);
|
||||||
} else if let Value::Int(int) = argument {
|
} else if let Value::Int(int) = argument {
|
||||||
min_int = min_int.min(*int);
|
min_int = min_int.min(*int);
|
||||||
} else {
|
|
||||||
return Err(EvalexprError::expected_number(argument.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (min_int as FloatType) < min_float {
|
|
||||||
Ok(Value::Int(min_int))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::Float(min_float))
|
return Err(EvalexprError::expected_number(argument.clone()));
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
)),
|
|
||||||
"max" => Some(Function::new(
|
|
||||||
Box::new(|argument| {
|
|
||||||
let arguments = expect_tuple(argument)?;
|
|
||||||
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 (min_int as FloatType) < min_float {
|
||||||
if let Value::Float(float) = argument {
|
Ok(Value::Int(min_int))
|
||||||
max_float = max_float.max(*float);
|
} else {
|
||||||
} else if let Value::Int(int) = argument {
|
Ok(Value::Float(min_float))
|
||||||
max_int = max_int.max(*int);
|
}
|
||||||
} else {
|
}))),
|
||||||
return Err(EvalexprError::expected_number(argument.clone()));
|
"max" => Some(Function::new(Box::new(|argument| {
|
||||||
}
|
let arguments = expect_tuple(argument)?;
|
||||||
}
|
let mut max_int = IntType::min_value();
|
||||||
|
let mut max_float = -1.0f64 / 0.0f64;
|
||||||
|
debug_assert!(max_float.is_infinite());
|
||||||
|
|
||||||
if (max_int as FloatType) > max_float {
|
for argument in arguments {
|
||||||
Ok(Value::Int(max_int))
|
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 {
|
} else {
|
||||||
Ok(Value::Float(max_float))
|
return Err(EvalexprError::expected_number(argument.clone()));
|
||||||
}
|
}
|
||||||
}),
|
}
|
||||||
)),
|
|
||||||
|
|
||||||
"len" => Some(Function::new(
|
if (max_int as FloatType) > max_float {
|
||||||
Box::new(|argument| {
|
Ok(Value::Int(max_int))
|
||||||
let subject = expect_string(argument)?;
|
} else {
|
||||||
Ok(Value::from(subject.len() as i64))
|
Ok(Value::Float(max_float))
|
||||||
}),
|
}
|
||||||
)),
|
}))),
|
||||||
|
|
||||||
|
"len" => Some(Function::new(Box::new(|argument| {
|
||||||
|
let subject = expect_string(argument)?;
|
||||||
|
Ok(Value::from(subject.len() as i64))
|
||||||
|
}))),
|
||||||
|
|
||||||
// string functions
|
// string functions
|
||||||
#[cfg(feature = "regex_support")]
|
#[cfg(feature = "regex_support")]
|
||||||
"str::regex_matches" => Some(Function::new(
|
"str::regex_matches" => Some(Function::new(Box::new(|argument| {
|
||||||
Box::new(|argument| {
|
let arguments = expect_tuple(argument)?;
|
||||||
let arguments = expect_tuple(argument)?;
|
|
||||||
|
|
||||||
let subject = expect_string(&arguments[0])?;
|
let subject = expect_string(&arguments[0])?;
|
||||||
let re_str = expect_string(&arguments[1])?;
|
let re_str = expect_string(&arguments[1])?;
|
||||||
match Regex::new(re_str) {
|
match Regex::new(re_str) {
|
||||||
Ok(re) => Ok(Value::Boolean(re.is_match(subject))),
|
Ok(re) => Ok(Value::Boolean(re.is_match(subject))),
|
||||||
Err(err) => Err(EvalexprError::invalid_regex(
|
Err(err) => Err(EvalexprError::invalid_regex(
|
||||||
re_str.to_string(),
|
re_str.to_string(),
|
||||||
format!("{}", err),
|
format!("{}", err),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}),
|
}))),
|
||||||
)),
|
|
||||||
#[cfg(feature = "regex_support")]
|
#[cfg(feature = "regex_support")]
|
||||||
"str::regex_replace" => Some(Function::new(
|
"str::regex_replace" => Some(Function::new(Box::new(|argument| {
|
||||||
Box::new(|argument| {
|
let arguments = expect_tuple(argument)?;
|
||||||
let arguments = expect_tuple(argument)?;
|
|
||||||
|
|
||||||
let subject = expect_string(&arguments[0])?;
|
let subject = expect_string(&arguments[0])?;
|
||||||
let re_str = expect_string(&arguments[1])?;
|
let re_str = expect_string(&arguments[1])?;
|
||||||
let repl = expect_string(&arguments[2])?;
|
let repl = expect_string(&arguments[2])?;
|
||||||
match Regex::new(re_str) {
|
match Regex::new(re_str) {
|
||||||
Ok(re) => Ok(Value::String(re.replace_all(subject, repl).to_string())),
|
Ok(re) => Ok(Value::String(re.replace_all(subject, repl).to_string())),
|
||||||
Err(err) => Err(EvalexprError::invalid_regex(
|
Err(err) => Err(EvalexprError::invalid_regex(
|
||||||
re_str.to_string(),
|
re_str.to_string(),
|
||||||
format!("{}", err),
|
format!("{}", err),
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}),
|
}))),
|
||||||
)),
|
"str::to_lowercase" => Some(Function::new(Box::new(|argument| {
|
||||||
"str::to_lowercase" => Some(Function::new(
|
let subject = expect_string(argument)?;
|
||||||
Box::new(|argument| {
|
Ok(Value::from(subject.to_lowercase()))
|
||||||
let subject = expect_string(argument)?;
|
}))),
|
||||||
Ok(Value::from(subject.to_lowercase()))
|
"str::to_uppercase" => Some(Function::new(Box::new(|argument| {
|
||||||
}),
|
let subject = expect_string(argument)?;
|
||||||
)),
|
Ok(Value::from(subject.to_uppercase()))
|
||||||
"str::to_uppercase" => Some(Function::new(
|
}))),
|
||||||
Box::new(|argument| {
|
"str::trim" => Some(Function::new(Box::new(|argument| {
|
||||||
let subject = expect_string(argument)?;
|
let subject = expect_string(argument)?;
|
||||||
Ok(Value::from(subject.to_uppercase()))
|
Ok(Value::from(subject.trim()))
|
||||||
}),
|
}))),
|
||||||
)),
|
|
||||||
"str::trim" => Some(Function::new(
|
|
||||||
Box::new(|argument| {
|
|
||||||
let subject = expect_string(argument)?;
|
|
||||||
Ok(Value::from(subject.trim()))
|
|
||||||
}),
|
|
||||||
)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use error::{EvalexprResult};
|
use error::EvalexprResult;
|
||||||
use value::Value;
|
use value::Value;
|
||||||
|
|
||||||
pub(crate) mod builtin;
|
pub(crate) mod builtin;
|
||||||
@ -27,12 +27,8 @@ impl Function {
|
|||||||
/// Creates a user-defined function.
|
/// Creates a user-defined function.
|
||||||
///
|
///
|
||||||
/// The `function` is a boxed function that takes a `Value` and returns a `EvalexprResult<Value, Error>`.
|
/// The `function` is a boxed function that takes a `Value` and returns a `EvalexprResult<Value, Error>`.
|
||||||
pub fn new(
|
pub fn new(function: Box<Fn(&Value) -> EvalexprResult<Value>>) -> Self {
|
||||||
function: Box<Fn(&Value) -> EvalexprResult<Value>>,
|
Self { function }
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
function,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn call(&self, argument: &Value) -> EvalexprResult<Value> {
|
pub(crate) fn call(&self, argument: &Value) -> EvalexprResult<Value> {
|
||||||
@ -42,9 +38,6 @@ impl Function {
|
|||||||
|
|
||||||
impl fmt::Debug for Function {
|
impl fmt::Debug for Function {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
write!(
|
write!(f, "Function {{ [...] }}")
|
||||||
f,
|
|
||||||
"Function {{ [...] }}"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,9 +420,7 @@ impl Operator {
|
|||||||
Ok(Value::Boolean(false))
|
Ok(Value::Boolean(false))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Tuple => {
|
Tuple => Ok(Value::Tuple(arguments.into())),
|
||||||
Ok(Value::Tuple(arguments.into()))
|
|
||||||
},
|
|
||||||
Assign => Err(EvalexprError::ContextNotManipulable),
|
Assign => Err(EvalexprError::ContextNotManipulable),
|
||||||
Chain => {
|
Chain => {
|
||||||
if arguments.is_empty() {
|
if arguments.is_empty() {
|
||||||
|
@ -410,11 +410,16 @@ impl Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collapse_root_stack_to(root_stack: &mut Vec<Node>, mut root: Node, collapse_goal: &Node) -> EvalexprResult<Node> {
|
fn collapse_root_stack_to(
|
||||||
|
root_stack: &mut Vec<Node>,
|
||||||
|
mut root: Node,
|
||||||
|
collapse_goal: &Node,
|
||||||
|
) -> EvalexprResult<Node> {
|
||||||
loop {
|
loop {
|
||||||
if let Some(mut potential_higher_root) = root_stack.pop() {
|
if let Some(mut potential_higher_root) = root_stack.pop() {
|
||||||
// TODO I'm not sure about this >, as I have no example for different sequence operators with the same precedence
|
// TODO I'm not sure about this >, as I have no example for different sequence operators with the same precedence
|
||||||
if potential_higher_root.operator().precedence() > collapse_goal.operator().precedence() {
|
if potential_higher_root.operator().precedence() > collapse_goal.operator().precedence()
|
||||||
|
{
|
||||||
potential_higher_root.children.push(root);
|
potential_higher_root.children.push(root);
|
||||||
root = potential_higher_root;
|
root = potential_higher_root;
|
||||||
} else {
|
} else {
|
||||||
@ -569,7 +574,7 @@ pub(crate) fn tokens_to_operator_tree(tokens: Vec<Token>) -> EvalexprResult<Node
|
|||||||
root_stack.push(node);
|
root_stack.push(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// println!("Stack after sequence operation: {:?}", root_stack);
|
// println!("Stack after sequence operation: {:?}", root_stack);
|
||||||
} else if root.operator().is_sequence() {
|
} else if root.operator().is_sequence() {
|
||||||
if let Some(mut last_root_child) = root.children.pop() {
|
if let Some(mut last_root_child) = root.children.pop() {
|
||||||
last_root_child.insert_back_prioritized(node, true)?;
|
last_root_child.insert_back_prioritized(node, true)?;
|
||||||
|
@ -137,17 +137,15 @@ fn test_functions() {
|
|||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"sub2".to_string(),
|
"sub2".to_string(),
|
||||||
Function::new(
|
Function::new(Box::new(|argument| {
|
||||||
Box::new(|argument| {
|
if let Value::Int(int) = argument {
|
||||||
if let Value::Int(int) = argument {
|
Ok(Value::Int(int - 2))
|
||||||
Ok(Value::Int(int - 2))
|
} else if let Value::Float(float) = argument {
|
||||||
} else if let Value::Float(float) = argument {
|
Ok(Value::Float(float - 2.0))
|
||||||
Ok(Value::Float(float - 2.0))
|
} else {
|
||||||
} else {
|
Err(EvalexprError::expected_number(argument.clone()))
|
||||||
Err(EvalexprError::expected_number(argument.clone()))
|
}
|
||||||
}
|
})),
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
context
|
context
|
||||||
@ -170,81 +168,76 @@ fn test_n_ary_functions() {
|
|||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"sub2".into(),
|
"sub2".into(),
|
||||||
Function::new(
|
Function::new(Box::new(|argument| {
|
||||||
Box::new(|argument| {
|
if let Value::Int(int) = argument {
|
||||||
if let Value::Int(int) = argument {
|
Ok(Value::Int(int - 2))
|
||||||
Ok(Value::Int(int - 2))
|
} else if let Value::Float(float) = argument {
|
||||||
} else if let Value::Float(float) = argument {
|
Ok(Value::Float(float - 2.0))
|
||||||
Ok(Value::Float(float - 2.0))
|
} else {
|
||||||
} else {
|
Err(EvalexprError::expected_number(argument.clone()))
|
||||||
Err(EvalexprError::expected_number(argument.clone()))
|
}
|
||||||
}
|
})),
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"avg".into(),
|
"avg".into(),
|
||||||
Function::new(
|
Function::new(Box::new(|argument| {
|
||||||
Box::new(|argument| {
|
let arguments = expect_tuple(argument)?;
|
||||||
let arguments = expect_tuple(argument)?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[1])?;
|
||||||
expect_number(&arguments[1])?;
|
|
||||||
|
|
||||||
if let (Value::Int(a), Value::Int(b)) = (&arguments[0], &arguments[1]) {
|
if let (Value::Int(a), Value::Int(b)) = (&arguments[0], &arguments[1]) {
|
||||||
Ok(Value::Int((a + b) / 2))
|
Ok(Value::Int((a + b) / 2))
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::Float(
|
Ok(Value::Float(
|
||||||
(arguments[0].as_float()? + arguments[1].as_float()?) / 2.0,
|
(arguments[0].as_float()? + arguments[1].as_float()?) / 2.0,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}),
|
})),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"muladd".into(),
|
"muladd".into(),
|
||||||
Function::new(
|
Function::new(Box::new(|argument| {
|
||||||
Box::new(|argument| {
|
let arguments = expect_tuple(argument)?;
|
||||||
let arguments = expect_tuple(argument)?;
|
expect_number(&arguments[0])?;
|
||||||
expect_number(&arguments[0])?;
|
expect_number(&arguments[1])?;
|
||||||
expect_number(&arguments[1])?;
|
expect_number(&arguments[2])?;
|
||||||
expect_number(&arguments[2])?;
|
|
||||||
|
|
||||||
if let (Value::Int(a), Value::Int(b), Value::Int(c)) =
|
if let (Value::Int(a), Value::Int(b), Value::Int(c)) =
|
||||||
(&arguments[0], &arguments[1], &arguments[2])
|
(&arguments[0], &arguments[1], &arguments[2])
|
||||||
{
|
{
|
||||||
Ok(Value::Int(a * b + c))
|
Ok(Value::Int(a * b + c))
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::Float(
|
Ok(Value::Float(
|
||||||
arguments[0].as_float()? * arguments[1].as_float()?
|
arguments[0].as_float()? * arguments[1].as_float()?
|
||||||
+ arguments[2].as_float()?,
|
+ arguments[2].as_float()?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}),
|
})),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
context
|
context
|
||||||
.set_function(
|
.set_function(
|
||||||
"count".into(),
|
"count".into(),
|
||||||
Function::new(
|
Function::new(Box::new(|arguments| match arguments {
|
||||||
Box::new(|arguments| {
|
Value::Tuple(tuple) => Ok(Value::from(tuple.len() as IntType)),
|
||||||
match arguments {
|
Value::Empty => Ok(Value::from(0)),
|
||||||
Value::Tuple(tuple) => Ok(Value::from(tuple.len() as IntType)),
|
_ => Ok(Value::from(1)),
|
||||||
Value::Empty => Ok(Value::from(0)),
|
})),
|
||||||
_ => Ok(Value::from(1)),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
context
|
context
|
||||||
.set_value("five".to_string(), Value::Int(5))
|
.set_value("five".to_string(), Value::Int(5))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
context.set_function("function_four".into(), Function::new(Box::new(|_| {Ok(Value::Int(4))}))).unwrap();
|
context
|
||||||
|
.set_function(
|
||||||
|
"function_four".into(),
|
||||||
|
Function::new(Box::new(|_| Ok(Value::Int(4)))),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(eval_with_context("avg(7, 5)", &context), Ok(Value::Int(6)));
|
assert_eq!(eval_with_context("avg(7, 5)", &context), Ok(Value::Int(6)));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -264,13 +257,19 @@ fn test_n_ary_functions() {
|
|||||||
Ok(Value::Int(14))
|
Ok(Value::Int(14))
|
||||||
);
|
);
|
||||||
assert_eq!(eval_with_context("count()", &context), Ok(Value::Int(0)));
|
assert_eq!(eval_with_context("count()", &context), Ok(Value::Int(0)));
|
||||||
assert_eq!(eval_with_context("count((1, 2, 3))", &context), Ok(Value::Int(3)));
|
assert_eq!(
|
||||||
|
eval_with_context("count((1, 2, 3))", &context),
|
||||||
|
Ok(Value::Int(3))
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
eval_with_context("count(3, 5.5, 2)", &context),
|
eval_with_context("count(3, 5.5, 2)", &context),
|
||||||
Ok(Value::Int(3))
|
Ok(Value::Int(3))
|
||||||
);
|
);
|
||||||
assert_eq!(eval_with_context("count 5", &context), Ok(Value::Int(1)));
|
assert_eq!(eval_with_context("count 5", &context), Ok(Value::Int(1)));
|
||||||
assert_eq!(eval_with_context("function_four()", &context), Ok(Value::Int(4)));
|
assert_eq!(
|
||||||
|
eval_with_context("function_four()", &context),
|
||||||
|
Ok(Value::Int(4))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user