ksl 0.1.30

KSL core library and interpreter
Documentation
//! # ksl::builtin::bit
//!
//! Built-in bitwise functions.
//!
//! - ShiftL
//! - ShiftR
//! - Band
//! - Bor
//! - Bxor

use crate::{Environment, eval::apply::eval_apply, value::Value};

pub(crate) fn shift_l(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
    if let [n, p] = args {
        match (eval_apply(n, env.clone())?, eval_apply(p, env.clone())?) {
            (Value::Number(num), Value::Number(pad)) if num.is_sign_positive() && pad.is_sign_positive() => Ok(Value::Number(
                ((num.trunc() as u64).unbounded_shl(pad.trunc() as u32)) as f64,
            )),
            (Value::Number(_), e) => Err(std::sync::Arc::from(format!(
                "Error[ksl::builtin::ShiftL]: Expected a non-negative integer as shifts, but got: `{e}`."
            ))),
            (e, _) => Err(std::sync::Arc::from(format!(
                "Error[ksl::builtin::ShiftL]: Expected a non-negative integer, but got: `{e}`."
            ))),
        }
    } else {
        Err(std::sync::Arc::from(format!(
            "Error[ksl::builtin::ShiftL]: Expected 2 parameters, but {} were passed.",
            args.len()
        )))
    }
}

pub(crate) fn shift_r(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
    if let [n, p] = args {
        match (eval_apply(n, env.clone())?, eval_apply(p, env)?) {
            (Value::Number(num), Value::Number(pad)) if num.is_sign_positive() && pad.is_sign_positive() => Ok(Value::Number(
                (num.trunc() as u64).unbounded_shr(pad.trunc() as u32) as f64,
            )),
            (Value::Number(_), e) => Err(std::sync::Arc::from(format!(
                "Error[ksl::builtin::ShiftR]: Expected a non-negative integer as shifts, but got: `{e}`."
            ))),
            (e, _) => Err(std::sync::Arc::from(format!(
                "Error[ksl::builtin::ShiftR]: Expected a non-negative integer, but got: `{e}`."
            ))),
        }
    } else {
        Err(std::sync::Arc::from(format!(
            "Error[ksl::builtin::ShiftR]: Expected 2 parameters, but {} were passed.",
            args.len()
        )))
    }
}

pub(crate) fn band(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
    if let [lhs, rhs] = args {
        match (eval_apply(lhs, env.clone())?, eval_apply(rhs, env.clone())?) {
            (Value::Number(l), Value::Number(r)) if l.is_sign_positive() && r.is_sign_positive() => Ok(Value::Number(
                std::ops::BitAnd::bitand(l.trunc() as u64, r.trunc() as u64) as f64,
            )),
            (Value::Number(_), e) | (e, _) => Err(std::sync::Arc::from(format!(
                "Error[ksl::builtin::Band]: Expected a non-negative integer, but got: `{e}`."
            ))),
        }
    } else {
        Err(std::sync::Arc::from(format!(
            "Error[ksl::builtin::Band]: Expected 2 parameter, but {} were passed.",
            args.len()
        )))
    }
}

pub(crate) fn bor(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
    if let [lhs, rhs] = args {
        match (eval_apply(lhs, env.clone())?, eval_apply(rhs, env.clone())?) {
            (Value::Number(l), Value::Number(r)) if l.is_sign_positive() && r.is_sign_positive() => Ok(Value::Number(
                std::ops::BitOr::bitor(l.trunc() as u64, r.trunc() as u64) as f64,
            )),
            (Value::Number(_), e) | (e, _) => Err(std::sync::Arc::from(format!(
                "Error[ksl::builtin::Bor]: Expected a non-negative integer, but got: `{e}`."
            ))),
        }
    } else {
        Err(std::sync::Arc::from(format!(
            "Error[ksl::builtin::Bor]: Expected 2 parameter, but {} were passed.",
            args.len()
        )))
    }
}

pub(crate) fn bxor(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
    if let [lhs, rhs] = args {
        match (eval_apply(lhs, env.clone())?, eval_apply(rhs, env.clone())?) {
            (Value::Number(l), Value::Number(r)) if l.is_sign_positive() && r.is_sign_positive() => Ok(Value::Number(
                std::ops::BitXor::bitxor(l.trunc() as u64, r.trunc() as u64) as f64,
            )),
            (Value::Number(_), e) | (e, _) => Err(std::sync::Arc::from(format!(
                "Error[ksl::builtin::Bxor]: Expected a non-negative integer, but got: `{e}`."
            ))),
        }
    } else {
        Err(std::sync::Arc::from(format!(
            "Error[ksl::builtin::Bxor]: Expected 2 parameter, but {} were passed.",
            args.len()
        )))
    }
}