Accept a negative operand after an operator in field arithmetic

Found while testing crates/doc/src/lib.rs:272

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-16 02:21:27 +07:00
committed by bflatastic
co-authored by Claude Haiku 5.5
parent 8b22b07e09
commit a59621fa78
2 changed files with 15 additions and 1 deletions
+4 -1
View File
@@ -273,7 +273,10 @@ fn parse_measure(s: &str, default: Unit) -> Option<f64> {
for op in ['+', '-', '*', '/'] {
// Past the first character, so a leading sign isn't an operator.
let skip = s.chars().next().map_or(0, char::len_utf8);
if let Some(i) = s[skip..].rfind(op).map(|i| i + skip) {
// A `+` or `-` right after another operator is the sign of its operand (`10*-2`, `5--3`).
let is_sign = |i: usize| matches!(op, '+' | '-') && s.get(..i).and_then(|l| l.trim_end().chars().last()).is_some_and(|c| "+-*/".contains(c));
let found = s.char_indices().rev().find(|&(i, c)| i >= skip && c == op && !is_sign(i));
if let Some(i) = found.map(|(i, _)| i) {
let (l, r) = (&s[..i], &s[i + 1..]);
if l.trim().is_empty() {
continue;
+11
View File
@@ -66,3 +66,14 @@ fn readouts_show_two_decimals() {
assert_eq!((Unit::Inches.number(595.2756), Unit::Points.number(595.2756)), ("8.2677".into(), "595.276".into()));
assert_eq!(Unit::Points.number(-0.00001), "0");
}
#[test]
fn a_negative_operand_after_an_operator_is_a_sign() {
assert_eq!(Unit::Points.parse("10*-2"), Some(-20.0));
assert_eq!(Unit::Points.parse("-10/-2"), Some(5.0));
assert_eq!(Unit::Points.parse("5--3"), Some(8.0));
assert_eq!(Unit::Points.parse("5 - -3"), Some(8.0));
assert_eq!(Unit::Points.parse("5+-3"), Some(2.0));
assert_eq!(Unit::Points.parse("10-2"), Some(8.0));
assert_eq!(super::parse_number("90*-1"), Some(-90.0));
}