skillet 0.6.3

Skillet: micro expression language (arithmetic, logical, functions, arrays, conditionals, excel formulas) made in Rust bin cli and server
Documentation
use crate::types::Value;
use crate::error::Error;

pub fn exec_logical(name: &str, args: &[Value]) -> Result<Value, Error> {
    match name {
        "__CONST_TRUE__" => Ok(Value::Boolean(true)),
        "__CONST_FALSE__" => Ok(Value::Boolean(false)),
        "__TERNARY__" => {
            if args.len() != 3 { return Err(Error::new("Ternary expects 3 args", None)); }
            let cond = args[0].as_bool().ok_or_else(|| Error::new("Ternary condition must be boolean", None))?;
            Ok(if cond { args[1].clone() } else { args[2].clone() })
        }
        "XOR" => {
            if args.len() != 2 { return Err(Error::new("XOR expects 2 arguments", None)); }
            let a = match &args[0] { Value::Boolean(b) => *b, Value::Number(n) => *n != 0.0, _ => false };
            let b = match &args[1] { Value::Boolean(b) => *b, Value::Number(n) => *n != 0.0, _ => false };
            Ok(Value::Boolean(a != b))
        }
        "AND" => {
            let mut result = true;
            for arg in args {
                let val = match arg { Value::Boolean(b) => *b, Value::Number(n) => *n != 0.0, _ => false };
                result = result && val;
                if !result { break; }
            }
            Ok(Value::Boolean(result))
        }
        "OR" => {
            let mut result = false;
            for arg in args {
                let val = match arg { Value::Boolean(b) => *b, Value::Number(n) => *n != 0.0, _ => false };
                result = result || val;
                if result { break; }
            }
            Ok(Value::Boolean(result))
        }
        "NOT" => {
            let val = match args.get(0) { Some(Value::Boolean(b)) => *b, Some(Value::Number(n)) => *n != 0.0, _ => false };
            Ok(Value::Boolean(!val))
        }
        "IF" => {
            if args.len() < 2 { return Err(Error::new("IF expects at least 2 arguments", None)); }
            let cond = match &args[0] { Value::Boolean(b) => *b, Value::Number(n) => *n != 0.0, _ => false };
            if cond {
                Ok(args[1].clone())
            } else {
                Ok(args.get(2).cloned().unwrap_or(Value::Boolean(false)))
            }
        }
        "IFS" => {
            if args.len() % 2 != 0 { return Err(Error::new("IFS expects pairs of condition,value arguments", None)); }
            for chunk in args.chunks(2) {
                if chunk.len() == 2 {
                    let cond = match &chunk[0] { Value::Boolean(b) => *b, Value::Number(n) => *n != 0.0, _ => false };
                    if cond {
                        return Ok(chunk[1].clone());
                    }
                }
            }
            Ok(Value::Boolean(false))
        }
        "BETWEEN" => {
            if args.len() != 3 { return Err(Error::new("BETWEEN expects 3 arguments: (min, max, value)", None)); }
            let min = args[0].as_number().ok_or_else(|| Error::new("BETWEEN min must be a number", None))?;
            let max = args[1].as_number().ok_or_else(|| Error::new("BETWEEN max must be a number", None))?;
            let value = args[2].as_number().ok_or_else(|| Error::new("BETWEEN value must be a number", None))?;
            Ok(Value::Boolean(value >= min && value <= max))
        }
        _ => Err(Error::new(format!("Unknown logical function: {}", name), None)),
    }
}