233 lines
7.3 KiB
Rust
233 lines
7.3 KiB
Rust
use crate::{
|
|
calc_result::CalcResult,
|
|
expressions::{parser::Node, token::Error, types::CellReferenceIndex},
|
|
model::Model,
|
|
};
|
|
|
|
// 2^48-1
|
|
const MAX: f64 = 281474976710655.0;
|
|
|
|
impl Model {
|
|
// BITAND( number1, number2)
|
|
pub(crate) fn fn_bitand(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 2 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
}
|
|
let number1 = match self.get_number(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let number2 = match self.get_number(&args[1], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
if number1.trunc() != number1 || number2.trunc() != number2 {
|
|
return CalcResult::new_error(Error::NUM, cell, "numbers must be integers".to_string());
|
|
}
|
|
if number1 < 0.0 || number2 < 0.0 {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"numbers must be positive or zero".to_string(),
|
|
);
|
|
}
|
|
|
|
if number1 > MAX || number2 > MAX {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"numbers must be less than 2^48-1".to_string(),
|
|
);
|
|
}
|
|
|
|
let number1 = number1.trunc() as i64;
|
|
let number2 = number2.trunc() as i64;
|
|
let result = number1 & number2;
|
|
CalcResult::Number(result as f64)
|
|
}
|
|
|
|
// BITOR(number1, number2)
|
|
pub(crate) fn fn_bitor(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 2 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
}
|
|
let number1 = match self.get_number(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let number2 = match self.get_number(&args[1], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
if number1.trunc() != number1 || number2.trunc() != number2 {
|
|
return CalcResult::new_error(Error::NUM, cell, "numbers must be integers".to_string());
|
|
}
|
|
if number1 < 0.0 || number2 < 0.0 {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"numbers must be positive or zero".to_string(),
|
|
);
|
|
}
|
|
|
|
if number1 > MAX || number2 > MAX {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"numbers must be less than 2^48-1".to_string(),
|
|
);
|
|
}
|
|
|
|
let number1 = number1.trunc() as i64;
|
|
let number2 = number2.trunc() as i64;
|
|
let result = number1 | number2;
|
|
CalcResult::Number(result as f64)
|
|
}
|
|
|
|
// BITXOR(number1, number2)
|
|
pub(crate) fn fn_bitxor(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 2 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
}
|
|
let number1 = match self.get_number(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let number2 = match self.get_number(&args[1], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
if number1.trunc() != number1 || number2.trunc() != number2 {
|
|
return CalcResult::new_error(Error::NUM, cell, "numbers must be integers".to_string());
|
|
}
|
|
if number1 < 0.0 || number2 < 0.0 {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"numbers must be positive or zero".to_string(),
|
|
);
|
|
}
|
|
|
|
if number1 > MAX || number2 > MAX {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"numbers must be less than 2^48-1".to_string(),
|
|
);
|
|
}
|
|
|
|
let number1 = number1.trunc() as i64;
|
|
let number2 = number2.trunc() as i64;
|
|
let result = number1 ^ number2;
|
|
CalcResult::Number(result as f64)
|
|
}
|
|
|
|
// BITLSHIFT(number, shift_amount)
|
|
pub(crate) fn fn_bitlshift(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 2 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
}
|
|
let number = match self.get_number(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let shift = match self.get_number(&args[1], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
if number.trunc() != number {
|
|
return CalcResult::new_error(Error::NUM, cell, "numbers must be integers".to_string());
|
|
}
|
|
if number < 0.0 {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"numbers must be positive or zero".to_string(),
|
|
);
|
|
}
|
|
|
|
if number > MAX {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"numbers must be less than 2^48-1".to_string(),
|
|
);
|
|
}
|
|
|
|
if shift.abs() > 53.0 {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"shift amount must be less than 53".to_string(),
|
|
);
|
|
}
|
|
|
|
let number = number.trunc() as i64;
|
|
let shift = shift.trunc() as i64;
|
|
let result = if shift > 0 {
|
|
number << shift
|
|
} else {
|
|
number >> -shift
|
|
};
|
|
let result = result as f64;
|
|
if result.abs() > MAX {
|
|
return CalcResult::new_error(Error::NUM, cell, "BITLSHIFT overflow".to_string());
|
|
}
|
|
CalcResult::Number(result)
|
|
}
|
|
|
|
// BITRSHIFT(number, shift_amount)
|
|
pub(crate) fn fn_bitrshift(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
|
|
if args.len() != 2 {
|
|
return CalcResult::new_args_number_error(cell);
|
|
}
|
|
let number = match self.get_number(&args[0], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
let shift = match self.get_number(&args[1], cell) {
|
|
Ok(f) => f,
|
|
Err(s) => return s,
|
|
};
|
|
if number.trunc() != number {
|
|
return CalcResult::new_error(Error::NUM, cell, "numbers must be integers".to_string());
|
|
}
|
|
if number < 0.0 {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"numbers must be positive or zero".to_string(),
|
|
);
|
|
}
|
|
|
|
if number > MAX {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"numbers must be less than 2^48-1".to_string(),
|
|
);
|
|
}
|
|
|
|
if shift.abs() > 53.0 {
|
|
return CalcResult::new_error(
|
|
Error::NUM,
|
|
cell,
|
|
"shift amount must be less than 53".to_string(),
|
|
);
|
|
}
|
|
|
|
let number = number.trunc() as i64;
|
|
let shift = shift.trunc() as i64;
|
|
let result = if shift > 0 {
|
|
number >> shift
|
|
} else {
|
|
number << -shift
|
|
};
|
|
let result = result as f64;
|
|
if result.abs() > MAX {
|
|
return CalcResult::new_error(Error::NUM, cell, "BITRSHIFT overflow".to_string());
|
|
}
|
|
CalcResult::Number(result)
|
|
}
|
|
}
|