locrian 0.2.2

A simple embeddable functional programming language.
Documentation
use crate::eval::{EvalResult, eval};

pub(crate) fn if_(args: Vec<EvalResult>) -> EvalResult {
    if let Some(EvalResult::Boolean(condition)) = args.first()
        && let Some(EvalResult::Quoted(then, ctx)) = args.get(1)
    {
        if *condition {
            eval(then.as_ref().clone(), ctx.clone()).unwrap_or(EvalResult::None)
        } else if let Some(EvalResult::Quoted(else_, ctx)) = args.get(2) {
            eval(else_.as_ref().clone(), ctx.clone()).unwrap_or(EvalResult::None)
        } else {
            EvalResult::None
        }
    } else {
        EvalResult::None
    }
}

pub(crate) fn not(args: Vec<EvalResult>) -> EvalResult {
    if let Some(EvalResult::Boolean(b)) = args.first() {
        EvalResult::Boolean(!b)
    } else {
        EvalResult::None
    }
}

pub(crate) fn eq(args: Vec<EvalResult>) -> EvalResult {
    EvalResult::Boolean(
        args.iter()
            .all(|x| args.first().map(|f| x == f).unwrap_or(false)),
    )
}

pub(crate) fn gt(args: Vec<EvalResult>) -> EvalResult {
    if let Some(EvalResult::Number(n1)) = args.first()
        && let Some(EvalResult::Number(n2)) = args.get(1)
    {
        EvalResult::Boolean(n1 > n2)
    } else {
        EvalResult::None
    }
}

pub(crate) fn lt(args: Vec<EvalResult>) -> EvalResult {
    if let Some(EvalResult::Number(n1)) = args.first()
        && let Some(EvalResult::Number(n2)) = args.get(1)
    {
        EvalResult::Boolean(n1 < n2)
    } else {
        EvalResult::None
    }
}

#[cfg(test)]
mod tests {

    use crate::{eval::EvalResult, eval_str, stdlib::STDLIB};

    #[test]
    fn test_if() {
        assert_eq!(
            eval_str(
                r#"use(["bool", "num"], 'if(true, 'add(2, 2), 'add(4, 4)))"#,
                STDLIB.clone()
            )
            .unwrap(),
            EvalResult::Number(4_f64)
        );
        assert_eq!(
            eval_str(
                r#"use(["bool", "num"], 'if(false, 'add(2, 2), 'add(4, 4)))"#,
                STDLIB.clone()
            )
            .unwrap(),
            EvalResult::Number(8_f64)
        );

        assert_eq!(
            eval_str(
                r#"use(["bool", "num"], 'if(eq(2, 3), 'add(2, 2), 'add(4, 4)))"#,
                STDLIB.clone()
            )
            .unwrap(),
            EvalResult::Number(8_f64)
        );

        assert_eq!(
            eval_str(
                r#"use(["bool", "num"], 'if(not(lt(2, 3)), 'add(2, 2), 'add(4, 4)))"#,
                STDLIB.clone()
            )
            .unwrap(),
            EvalResult::Number(8_f64)
        );
        assert_eq!(
            eval_str(
                r#"use(["bool", "num"], 'if(gt(2, 3), 'add(2, 2), 'add(4, 4)))"#,
                STDLIB.clone()
            )
            .unwrap(),
            EvalResult::Number(8_f64)
        );
    }
}