Make builtin len support tuples

Implements #41
This commit is contained in:
Sebastian Schmidt 2019-08-29 11:10:54 +03:00
parent 15cdb3eb50
commit b9c4b34a2f
7 changed files with 19 additions and 13 deletions

View File

@ -282,7 +282,7 @@ This crate offers a set of builtin functions.
|------------|-----------------|----------------|-------------|
| `min` | >= 1 | Numeric | Returns the minimum of the arguments |
| `max` | >= 1 | Numeric | Returns the maximum of the arguments |
| `len` | 1 | String | Returns the character length of a string |
| `len` | 1 | String/Tuple | Returns the character length of a string, or the amount of elements in a tuple (not recursively) |
| `str::regex_matches` | 2 | String, String | Returns true if the first argument matches the regex in the second argument |
| `str::regex_replace` | 3 | String, String, String | Returns the first argument with all matches of the regex in the second argument replaced by the third argument |
| `str::to_lowercase` | 1 | String | Returns the lower-case version of the string |

View File

@ -5,10 +5,7 @@
//! The module also contains some helper functions starting with `expect_` that check for a condition and return `Err(_)` if the condition is not fulfilled.
//! They are meant as shortcuts to not write the same error checking code everywhere.
use crate::{
token::PartialToken,
value::{value_type::ValueType, TupleType},
};
use crate::{token::PartialToken, value::value_type::ValueType};
use crate::value::Value;
@ -110,7 +107,7 @@ pub enum EvalexprError {
/// Only use this if there is no other error that describes the expected and provided types in more detail.
TypeError {
/// The expected types.
expected: TupleType,
expected: Vec<ValueType>,
/// The actual value.
actual: Value,
},
@ -205,7 +202,7 @@ impl EvalexprError {
}
/// Constructs `Error::TypeError{actual, expected}`.
pub fn type_error(actual: Value, expected: TupleType) -> Self {
pub fn type_error(actual: Value, expected: Vec<ValueType>) -> Self {
EvalexprError::TypeError { actual, expected }
}

View File

@ -3,7 +3,7 @@ use regex::Regex;
use crate::{
value::{FloatType, IntType},
EvalexprError, Function, Value,
EvalexprError, Function, Value, ValueType,
};
pub fn builtin_function(identifier: &str) -> Option<Function> {
@ -54,8 +54,16 @@ pub fn builtin_function(identifier: &str) -> Option<Function> {
}))),
"len" => Some(Function::new(Box::new(|argument| {
let subject = argument.as_string()?;
Ok(Value::from(subject.len() as i64))
if let Ok(subject) = argument.as_string() {
Ok(Value::from(subject.len() as i64))
} else if let Ok(subject) = argument.as_tuple() {
Ok(Value::from(subject.len() as i64))
} else {
Err(EvalexprError::type_error(
argument.clone(),
vec![ValueType::String, ValueType::Tuple],
))
}
}))),
// string functions

View File

@ -269,7 +269,7 @@
//! |------------|-----------------|----------------|-------------|
//! | `min` | >= 1 | Numeric | Returns the minimum of the arguments |
//! | `max` | >= 1 | Numeric | Returns the maximum of the arguments |
//! | `len` | 1 | String | Returns the character length of a string |
//! | `len` | 1 | String/Tuple | Returns the character length of a string, or the amount of elements in a tuple (not recursively) |
//! | `str::regex_matches` | 2 | String, String | Returns true if the first argument matches the regex in the second argument |
//! | `str::regex_replace` | 3 | String, String, String | Returns the first argument with all matches of the regex in the second argument replaced by the third argument |
//! | `str::to_lowercase` | 1 | String | Returns the lower-case version of the string |

View File

@ -1,7 +1,7 @@
use crate::Value;
/// The type of a `Value`.
#[derive(Clone, Copy, Eq, PartialEq)]
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum ValueType {
/// The `Value::String` type.
String,

View File

@ -277,6 +277,7 @@ fn test_builtin_functions() {
assert_eq!(eval("min(4.0, 3)"), Ok(Value::Int(3)));
assert_eq!(eval("max(4.0, 3)"), Ok(Value::Float(4.0)));
assert_eq!(eval("len(\"foobar\")"), Ok(Value::Int(6)));
assert_eq!(eval("len(\"a\", \"b\")"), Ok(Value::Int(2)));
assert_eq!(
eval("str::to_lowercase(\"FOOBAR\")"),
Ok(Value::from("foobar"))

View File

@ -27,4 +27,4 @@ fn test_regex_functions() {
eval("str::regex_replace(\"foobar\", \".*?(i+)\", \"b$1\")"),
Ok(Value::String("foobar".to_owned()))
);
}
}