diff --git a/src/main.rs b/src/main.rs index 5a73914..84c33ab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,9 +18,47 @@ fn main() { } }; + println!("{}", parse_and_calc_humanreadable(input)); +} + +pub fn parse_and_calc_humanreadable(mut input: String) -> String { + let should_add_back_equals = if let Some((i, _)) = input + .chars() + .enumerate() + .filter(|(_, c)| !matches!(c, ' ' | '&' | '\n')) + .find(|(_, c)| *c == '=') + { + input.remove(i); + true + } else { + false + }; + + // no need to remove the character here, + // as we ignore the ampersand in all other logic already + let should_add_back_alignment = input.contains('&'); + let result = parse_and_calc(&input); - println!("{result:.0$}", get_significant_digits(&result)); + format!( + "{0}{result:.1$}", + if should_add_back_equals && should_add_back_alignment { + "& = " + } else if should_add_back_equals { + "= " + } else if should_add_back_alignment { + "& " + } else { + "" + }, + get_significant_digits(&result), + ) +} +#[test] +fn test_equals_readdition() { + assert_eq!(parse_and_calc_humanreadable(" = 11".into()), "= 11"); + assert_eq!(parse_and_calc_humanreadable(" &= 11".into()), "& = 11"); + assert_eq!(parse_and_calc_humanreadable(" & 11".into()), "& 11"); } pub fn parse_and_calc(s: &str) -> Float { diff --git a/src/nodes/from_str.rs b/src/nodes/from_str.rs index ba94dfa..14e4c9a 100644 --- a/src/nodes/from_str.rs +++ b/src/nodes/from_str.rs @@ -22,7 +22,7 @@ impl TryFrom for Operator { fn try_from(value: char) -> Result { match value { '+' => Ok(Self::Plus), - '-' => Ok(Self::Minus), + '-' | '−' => Ok(Self::Minus), '*' | '×' => Ok(Self::Mult), '/' | '÷' => Ok(Self::Div), '^' => Ok(Self::Exp), @@ -79,11 +79,12 @@ impl FromStr for Nodes { } /// A function to check if the given `char` should be used by the parser. /// - /// We ignore whitespace since it has no semantic significance in typst aside from variables, - /// (which are not implemented) + /// We ignore whitespace since it has no semantic significance in typst + /// (aside from variables, which are not implemented) /// and `&` because it is only used for visual alignment. /// - /// Newlines are also ignored because they're likely accidental; like in the case of `echo 1+1 | tylc`. + /// Newlines are also ignored because they're likely accidental; + /// like in the case of `echo 1+1 | tylc`. fn is_not_ignored_char(c: &char) -> bool { !matches!(c, ' ' | '&' | '\n') } @@ -112,7 +113,10 @@ impl FromStr for Nodes { } } ParsingState::ReadingNumber(start_index) => { - if !is_number_char(c) { + if !is_number_char(c) + // don't stop reading number on a special case, eg "1e-1" + && !(filtered_string.chars().nth(i - 1) == Some('e') && c == '-') + { nodes.push(Node::Number( Float::parse(&filtered_string[start_index..i]) .map_err(|e| { @@ -181,6 +185,6 @@ impl FromStr for Nodes { } } - Ok(Nodes(nodes)) + Ok(Self(nodes)) } } diff --git a/src/nodes/tests.rs b/src/nodes/tests.rs index 405efe5..2acaac0 100644 --- a/src/nodes/tests.rs +++ b/src/nodes/tests.rs @@ -5,6 +5,11 @@ use rug::Float; use crate::nodes::{Function, Node, Nodes, Operator, PREC}; +#[test] +fn e_edge_case() { + assert_eq!(Nodes::from_str("1e-1").unwrap().evaluate().to_f64(), 0.1) +} + #[test] fn implicit_mult() { assert_eq!(