Skip to content

Commit

Permalink
Support large roman numerals with an overline
Browse files Browse the repository at this point in the history
Close #282
  • Loading branch information
printfn committed Sep 27, 2024
1 parent 41ddfef commit f68843e
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 9 deletions.
24 changes: 19 additions & 5 deletions core/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ fn evaluate_as<I: Interrupt>(
if a == 0 {
return Err(FendError::RomanNumeralZero);
}
let upper_limit = 100_000;
let upper_limit = 1_000_000_000;
if a > upper_limit {
return Err(FendError::OutOfRange {
value: Box::new(a),
Expand All @@ -640,7 +640,7 @@ fn evaluate_as<I: Interrupt>(
},
});
}
return Ok(Value::String(borrow::Cow::Owned(to_roman(a))));
return Ok(Value::String(borrow::Cow::Owned(to_roman(a, true))));
}
"words" => {
let uint = evaluate(a, scope, attrs, context, int)?
Expand Down Expand Up @@ -823,10 +823,10 @@ fn resolve_builtin_identifier<I: Interrupt>(
})
}

fn to_roman(mut num: usize) -> String {
fn to_roman(mut num: usize, large: bool) -> String {
// based on https://stackoverflow.com/a/41358305
let mut result = String::new();
for (r, n) in [
let values = [
("M", 1000),
("CM", 900),
("D", 500),
Expand All @@ -840,7 +840,21 @@ fn to_roman(mut num: usize) -> String {
("V", 5),
("IV", 4),
("I", 1),
] {
];
if large {
for (r, mut n) in &values[0..values.len() - 1] {
n *= 1000;
let q = num / n;
num -= q * n;
for _ in 0..q {
for ch in r.chars() {
result.push(ch);
result.push('\u{305}'); // combining overline
}
}
}
}
for (r, n) in values {
let q = num / n;
num -= q * n;
for _ in 0..q {
Expand Down
2 changes: 1 addition & 1 deletion core/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ fn parse_symbol(ch: char, input: &mut &str) -> FResult<Token> {
Symbol::Equals
}
}
'\u{2260}' => Symbol::NotEquals, // unicode not equal to symbol
'\u{2260}' => Symbol::NotEquals, // unicode not equal to symbol
'\\' | '\u{3bb}' => Symbol::Backslash, // lambda symbol
'.' => Symbol::Dot,
'<' => {
Expand Down
6 changes: 3 additions & 3 deletions core/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5940,10 +5940,10 @@ fn test_roman() {
test_eval_simple("2020 to roman", "MMXX");
test_eval_simple("3456 to roman", "MMMCDLVI");
test_eval_simple("1452 to roman", "MCDLII");
test_eval_simple("20002 to roman", "MMMMMMMMMMMMMMMMMMMMII");
test_eval_simple("20002 to roman", "X\u{305}X\u{305}II");
expect_error(
"100001 to roman",
Some("100001 must lie in the interval [1, 100000]"),
"1000000001 to roman",
Some("1000000001 must lie in the interval [1, 1000000000]"),
);
}

Expand Down

0 comments on commit f68843e

Please sign in to comment.