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()
)))
}
}