use crate::{Error, TulispContext, TulispObject, TulispValue, destruct_eval_bind};
fn string_cmp(
ctx: &mut TulispContext,
args: &TulispObject,
oper: impl Fn(&str, &str) -> bool,
) -> Result<TulispObject, Error> {
let args_other = args;
destruct_eval_bind!(ctx, (string1 string2) = args_other);
let string1 = string1.inner_ref();
let string2 = string2.inner_ref();
match (&string1.0, &string2.0) {
(TulispValue::String { value: string1 }, TulispValue::String { value: string2 }) => {
Ok(oper(string1, string2).into())
}
(_, _) => Err(
Error::type_mismatch("Both arguments need to be strings".to_string()).with_trace(
if string1.0.stringp() {
args.cadr()?
} else {
args.car()?
},
),
),
}
}
pub(crate) fn add(ctx: &mut TulispContext) {
ctx.defspecial("string<", |ctx, args| string_cmp(ctx, args, PartialOrd::lt));
ctx.defspecial("string>", |ctx, args| string_cmp(ctx, args, PartialOrd::gt));
ctx.defspecial("string=", |ctx, args| string_cmp(ctx, args, PartialEq::eq));
ctx.defspecial("string-lessp", |ctx, args| {
string_cmp(ctx, args, PartialOrd::lt)
});
ctx.defspecial("string-greaterp", |ctx, args| {
string_cmp(ctx, args, PartialOrd::gt)
});
ctx.defspecial("string-equal", |ctx, args| {
string_cmp(ctx, args, PartialEq::eq)
});
}
#[cfg(test)]
mod tests {
use crate::{
TulispContext,
test_utils::{eval_assert, eval_assert_not},
};
#[test]
fn test_string_comparison() {
let ctx = &mut TulispContext::new();
eval_assert(ctx, r#"(string< "hello" "world")"#);
eval_assert(ctx, r#"(string> "world" "hello")"#);
eval_assert(ctx, r#"(string= "hello" "hello")"#);
eval_assert(ctx, r#"(string-lessp "hello" "world")"#);
eval_assert(ctx, r#"(string-greaterp "world" "hello")"#);
eval_assert(ctx, r#"(string-equal "hello" "hello")"#);
eval_assert_not(ctx, r#"(string< "hello" "hello")"#);
eval_assert_not(ctx, r#"(string< "world" "hello")"#);
eval_assert_not(ctx, r#"(string> "hello" "world")"#);
eval_assert_not(ctx, r#"(string> "hello" "hello")"#);
eval_assert_not(ctx, r#"(string= "hello" "world")"#);
eval_assert_not(ctx, r#"(string= "world" "hello")"#);
eval_assert_not(ctx, r#"(string-lessp "hello" "hello")"#);
eval_assert_not(ctx, r#"(string-lessp "world" "hello")"#);
eval_assert_not(ctx, r#"(string-greaterp "hello" "world")"#);
eval_assert_not(ctx, r#"(string-greaterp "hello" "hello")"#);
eval_assert_not(ctx, r#"(string-equal "hello" "world")"#);
eval_assert_not(ctx, r#"(string-equal "world" "hello")"#);
}
}