Compare commits

...
Author SHA1 Message Date
9794e0c9d5
refactor: maybe more efficient rsplit_once_last 2026-10-19 00:21:32 -07:00
e23327c08f
refactor: loosen lifetime bounds 2026-10-19 00:19:35 -07:00
0f937fe9a8
fix(formatting): split on last match
the implementation doesn't look very performant,
since it calls rfind and then rsplit_once.
using split_at to replace the second call is a little more difficult tho
2026-10-19 00:18:05 -07:00
58b3d876e4
fix: constant implicit mult
before, "pi 2" caused a panic while "2 pi" worked just fine.
now both directions work :)
2026-10-18 22:30:39 -07:00
3 changed files with 30 additions and 16 deletions

View file

@ -3,7 +3,7 @@ use rug::Float;
use crate::nodes::{self, Error}; use crate::nodes::{self, Error};
pub fn pretty_eval(input: &str, max_digits: usize) -> Result<String, Error> { pub fn pretty_eval(input: &str, max_digits: usize) -> Result<String, Error> {
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, // no need to remove the character here,
// as we ignore it in all other logic already // as we ignore it in all other logic already
@ -32,22 +32,16 @@ pub fn pretty_eval(input: &str, max_digits: usize) -> Result<String, Error> {
} }
trait StrExt { trait StrExt {
fn rsplit_once_any<'a>( fn rsplit_once_last<'a, 'b>(&'a self, delimiters: &[&'b str]) -> (&'a str, &'b str, &'a str);
&'a self,
delimiters: &[&'static str],
) -> (&'a str, &'static str, &'a str);
} }
impl StrExt for str { impl StrExt for str {
fn rsplit_once_any<'a>( fn rsplit_once_last<'a, 'b>(&'a self, delimiters: &[&'b str]) -> (&'a str, &'b str, &'a str) {
&'a self, delimiters
delimiters: &[&'static str], .iter()
) -> (&'a str, &'static str, &'a str) { .filter_map(|delimiter| self.rfind(delimiter).map(|i| (delimiter, i)))
for delimiter in delimiters { .max_by_key(|(_, i)| *i)
if let Some((prefix, suffix)) = self.rsplit_once(delimiter) { .map(|(delimiter, i)| (&self[..i], *delimiter, &self[i + delimiter.len()..]))
return (prefix, delimiter, suffix); .unwrap_or(("", "", self))
}
}
return ("", "", self);
} }
} }
@ -124,6 +118,14 @@ mod tests {
assert_eq!(pretty_eval("-11", MAX_DIGITS).unwrap(), "-11"); 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] #[test]
fn basic_get_significant_digits() { fn basic_get_significant_digits() {
let many_zeros = eval("14.00643 + 1.00784 * 4 + 35.446 + 15.9994 * 4"); let many_zeros = eval("14.00643 + 1.00784 * 4 + 35.446 + 15.9994 * 4");

View file

@ -126,6 +126,12 @@ impl FromStr for Nodes {
&& !(c == 'e' && filtered_string.chars().nth(i + 1).is_some_and(|c| c == '-')) && !(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')) && !(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( nodes.push(Node::from(
Float::parse(&filtered_string[start_index..i]).map_err(|e| { Float::parse(&filtered_string[start_index..i]).map_err(|e| {
Error::NumberParsing(filtered_string[start_index..i].to_owned(), e) Error::NumberParsing(filtered_string[start_index..i].to_owned(), e)
@ -180,7 +186,7 @@ impl FromStr for Nodes {
); );
} }
ParsingState::ReadingNumber(start_index) => { 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::Operator(Default::default()));
} }
nodes.push(Node::from( nodes.push(Node::from(

View file

@ -38,3 +38,9 @@ fn unary_operators() {
assert_eq!(eval("-10"), -10.); assert_eq!(eval("-10"), -10.);
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);
}