feat: add "e" as a constant

this is not great, because due to lacking whitespace-awareness
`e sin(1)` evaluates as `esin(1)` which does not exist.
This commit is contained in:
electria 2026-10-04 16:04:25 -07:00
commit d8dc549954
Signed by: electria
SSH key fingerprint: SHA256:8LlB3ucPbBHqozqkhsNbaV5oG3SlzzqUj8FZDL6IPQs

View file

@ -13,6 +13,7 @@ impl Node {
"pi" => Self::Number(Float::with_val(PREC, f64::consts::PI)), "pi" => Self::Number(Float::with_val(PREC, f64::consts::PI)),
// Planck's constant, in J*s (joule-seconds) // Planck's constant, in J*s (joule-seconds)
"h" => Self::Number(Float::with_val(PREC, 6.62607015e-34)), "h" => Self::Number(Float::with_val(PREC, 6.62607015e-34)),
"e" => Self::Number(Float::with_val(PREC, f64::consts::E)),
_ => Self::Function(s.parse()?), _ => Self::Function(s.parse()?),
}) })
} }
@ -70,10 +71,14 @@ impl FromStr for Nodes {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
/// A superset of `char::is_numeric` /// A superset of `char::is_numeric`
/// that includes other characters parseable into numbers, /// that includes other characters parseable into numbers,
/// such as `.` (for decimal) and `e` for scientific notation. /// now only `.` (for decimals)
///
/// since including `e` makes it not parsable as a constant,
/// this function effectively only checks if the character can *start* a number
/// (since a number cannot start with `e`)
fn is_number_char(c: char) -> bool { fn is_number_char(c: char) -> bool {
match c { match c {
'.' | 'e' => true, '.' => true,
c => c.is_numeric(), c => c.is_numeric(),
} }
} }
@ -114,8 +119,10 @@ impl FromStr for Nodes {
} }
ParsingState::ReadingNumber(start_index) => { 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" && !(c == 'e' && filtered_string.chars().nth(i + 1).is_some_and(char::is_numeric))
&& !(filtered_string.chars().nth(i - 1) == Some('e') && c == '-') // don't stop reading number on special case eg "1e-1"
&& !(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'))
{ {
nodes.push(Node::Number( nodes.push(Node::Number(
Float::parse(&filtered_string[start_index..i]) Float::parse(&filtered_string[start_index..i])
@ -203,3 +210,16 @@ fn test() {
], ],
) )
} }
#[test]
fn test_e() {
assert_eq!(
Nodes::from_str("5e * 5").unwrap().as_ref(),
&[
Node::Number(Float::with_val(PREC, 5)),
Node::Operator(Operator::Mult),
Node::Number(Float::with_val(PREC, f64::consts::E)),
Node::Operator(Operator::Mult),
Node::Number(Float::with_val(PREC, 5))
],
)
}