UPDATE: Adds ARABIC and ROMAN (#509)

This commit is contained in:
Nicolás Hatcher Andrés
2025-11-03 23:44:22 +01:00
committed by GitHub
parent 7f57826371
commit e5854ab3d7
5 changed files with 306 additions and 1 deletions

View File

@@ -2,6 +2,7 @@ use crate::cast::NumberOrArray;
use crate::constants::{LAST_COLUMN, LAST_ROW};
use crate::expressions::parser::ArrayNode;
use crate::expressions::types::CellReferenceIndex;
use crate::functions::math_util::{from_roman, to_roman_with_form};
use crate::number_format::to_precision;
use crate::single_number_fn;
use crate::{
@@ -1376,4 +1377,92 @@ impl Model {
}
CalcResult::Number((x + random() * (y - x)).floor())
}
pub(crate) fn fn_roman(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
if args.is_empty() || args.len() > 2 {
return CalcResult::new_args_number_error(cell);
}
let number = match self.get_number(&args[0], cell) {
Ok(f) => f.floor(),
Err(s) => return s,
};
if number == 0.0 {
return CalcResult::String(String::new());
}
if !(0.0..=3999.0).contains(&number) {
return CalcResult::Error {
error: Error::VALUE,
origin: cell,
message: "Number must be between 0 and 3999".to_string(),
};
}
let form = if args.len() == 2 {
let mut t = match self.get_number(&args[1], cell) {
Ok(f) => f as i32,
Err(s) => return s,
};
// If the value is a boolean TRUE/FALSE, convert to 0/4
if t == 0 || t == 1 {
if let CalcResult::Boolean(b) = self.evaluate_node_in_context(&args[1], cell) {
if b {
// classic form
t = 0;
} else {
// simplified form
t = 4;
}
}
}
t
} else {
0
};
if !(0..=4).contains(&form) {
return CalcResult::Error {
error: Error::VALUE,
origin: cell,
message: "Form must be between 0 and 4".to_string(),
};
}
let roman_numeral = match to_roman_with_form(number as u32, form) {
Ok(s) => s,
Err(e) => {
return CalcResult::Error {
error: Error::VALUE,
origin: cell,
message: format!("Could not convert to Roman numeral: {e}"),
}
}
};
CalcResult::String(roman_numeral)
}
pub(crate) fn fn_arabic(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
if args.len() != 1 {
return CalcResult::new_args_number_error(cell);
}
let roman_numeral = match self.evaluate_node_in_context(&args[0], cell) {
CalcResult::String(s) => s,
error @ CalcResult::Error { .. } => return error,
_ => {
return CalcResult::Error {
error: Error::VALUE,
origin: cell,
message: "Argument must be a text string".to_string(),
}
}
};
if roman_numeral.is_empty() {
return CalcResult::Number(0.0);
}
match from_roman(&roman_numeral) {
Ok(value) => CalcResult::Number(value as f64),
Err(e) => CalcResult::Error {
error: Error::VALUE,
origin: cell,
message: format!("Invalid Roman numeral: {e}"),
},
}
}
}