diff --git a/src/formatting.rs b/src/formatting.rs index 5d492ab..c1853da 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -3,7 +3,7 @@ use rug::Float; use crate::nodes::{self, Error}; pub fn pretty_eval(input: &str, max_digits: usize) -> Result { - let (prefix, deliminator, input) = input.rsplit_once_any(&["plus.minus ", "& ", "= "]); + let (prefix, deliminator, input) = input.rsplit_once_last(&["= ", "& ", "plus.minus "]); // no need to remove the character here, // as we ignore it in all other logic already @@ -32,22 +32,16 @@ pub fn pretty_eval(input: &str, max_digits: usize) -> Result { } trait StrExt { - fn rsplit_once_any<'a>( - &'a self, - delimiters: &[&'static str], - ) -> (&'a str, &'static str, &'a str); + fn rsplit_once_last<'a, 'b>(&'a self, delimiters: &[&'b str]) -> (&'a str, &'b str, &'a str); } impl StrExt for str { - fn rsplit_once_any<'a>( - &'a self, - delimiters: &[&'static str], - ) -> (&'a str, &'static str, &'a str) { - for delimiter in delimiters { - if let Some((prefix, suffix)) = self.rsplit_once(delimiter) { - return (prefix, delimiter, suffix); - } - } - return ("", "", self); + fn rsplit_once_last<'a, 'b>(&'a self, delimiters: &[&'b str]) -> (&'a str, &'b str, &'a str) { + delimiters + .iter() + .filter_map(|delimiter| self.rfind(delimiter).map(|i| (delimiter, i))) + .max_by_key(|(_, i)| *i) + .map(|(delimiter, i)| (&self[..i], *delimiter, &self[i + delimiter.len()..])) + .unwrap_or(("", "", self)) } } @@ -124,6 +118,14 @@ mod tests { assert_eq!(pretty_eval("-11", MAX_DIGITS).unwrap(), "-11"); } + #[test] + fn complex_prefix() { + assert_eq!( + pretty_eval("plus.minus 5 & = 5", MAX_DIGITS).unwrap(), + "plus.minus 5 & = 5" + ); + } + #[test] fn basic_get_significant_digits() { let many_zeros = eval("14.00643 + 1.00784 * 4 + 35.446 + 15.9994 * 4"); diff --git a/src/nodes/parse.rs b/src/nodes/parse.rs index 0405be0..ec44b3f 100644 --- a/src/nodes/parse.rs +++ b/src/nodes/parse.rs @@ -126,6 +126,12 @@ impl FromStr for Nodes { && !(c == 'e' && filtered_string.chars().nth(i + 1).is_some_and(|c| c == '-')) && !(c == '-' && filtered_string.chars().nth(i - 1).is_some_and(|c| c == 'e')) { + // likely a constant before this number + // no need to check for parenthesis here though (why?) + if matches!(nodes.last(), Some(Node::Number(_))) { + nodes.push(Node::Operator(Default::default())); + } + nodes.push(Node::from( Float::parse(&filtered_string[start_index..i]).map_err(|e| { Error::NumberParsing(filtered_string[start_index..i].to_owned(), e) @@ -180,7 +186,7 @@ impl FromStr for Nodes { ); } ParsingState::ReadingNumber(start_index) => { - if matches!(nodes.last(), Some(Node::ParenthesisEnd)) { + if matches!(nodes.last(), Some(Node::ParenthesisEnd | Node::Number(_))) { nodes.push(Node::Operator(Default::default())); } nodes.push(Node::from( diff --git a/src/nodes/tests.rs b/src/nodes/tests.rs index 1d40f50..d7cbd59 100644 --- a/src/nodes/tests.rs +++ b/src/nodes/tests.rs @@ -38,3 +38,9 @@ fn unary_operators() { assert_eq!(eval("-10"), -10.); assert_eq!(eval("+10"), 10.); } + +#[test] +fn constant_implicit_mult() { + assert_eq!(eval("2pi"), 6.283185307179586); + assert_eq!(eval("pi2"), 6.283185307179586); +}