feat: nodes to num

co-authored by electria
This commit is contained in:
Edeth-Baguette 2026-07-13 17:13:54 -07:00
commit 06aaf8cb8a

View file

@ -1,7 +1,11 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::str::FromStr; use std::str::FromStr;
use rug::{Float, float::ParseFloatError, ops::CompleteRound}; use rug::{
Float,
float::ParseFloatError,
ops::{CompleteRound, Pow},
};
#[derive(Clone, Debug, thiserror::Error)] #[derive(Clone, Debug, thiserror::Error)]
enum Error { enum Error {
@ -28,6 +32,9 @@ enum Node {
enum Operator { enum Operator {
Plus, Plus,
Minus, Minus,
Mult,
Div,
Exp,
} }
impl TryFrom<char> for Operator { impl TryFrom<char> for Operator {
type Error = (); type Error = ();
@ -35,6 +42,9 @@ impl TryFrom<char> for Operator {
match value { match value {
'+' => Ok(Self::Plus), '+' => Ok(Self::Plus),
'-' => Ok(Self::Minus), '-' => Ok(Self::Minus),
'*' => Ok(Self::Mult),
'/' => Ok(Self::Div),
'^' => Ok(Self::Exp),
_ => Err(()), _ => Err(()),
} }
} }
@ -148,6 +158,177 @@ fn nodes_from_str(s: &str) -> Result<Vec<Node>, Error> {
Ok(nodes) Ok(nodes)
} }
fn collapse_toplevel(nodes: &mut Vec<Node>, mut end: usize) {
let start = nodes[0..end]
.iter()
.rposition(|n| *n == Node::ParenthesisStart)
.unwrap_or(0);
while let Some(operator) = nodes[start..end]
.iter()
.position(|n| *n == Node::Function(Function::Sine))
{
match &mut nodes[start..end][operator + 1] {
Node::Number(n) => n.sin_mut(),
_ => panic!("operator is missing an operand"),
};
nodes.remove(operator);
end -= 1;
}
while let Some(operator) = nodes[start..end]
.iter()
.position(|n| *n == Node::Function(Function::Cosine))
{
match &mut nodes[start..end][operator + 1] {
Node::Number(n) => n.cos_mut(),
_ => panic!("operator is missing an operand"),
};
nodes.remove(operator);
end -= 1;
}
while let Some(operator) = nodes[start..end]
.iter()
.position(|n| *n == Node::Operator(Operator::Exp))
{
let lhs = match &nodes[start..end][operator - 1] {
Node::Number(n) => n,
_ => panic!("operator is missing an operand"),
};
let rhs = match &nodes[start..end][operator + 1] {
Node::Number(n) => n,
_ => panic!("operator is missing an operand"),
};
let number = lhs.pow(rhs).complete(PREC);
nodes.remove(operator - 1);
nodes.remove(operator - 1);
end -= 2;
nodes[operator - 1] = Node::Number(number);
}
while let Some(operator) = nodes[start..end]
.iter()
.position(|n| *n == Node::Operator(Operator::Mult))
{
let lhs = match &nodes[start..end][operator - 1] {
Node::Number(n) => n,
_ => panic!("operator is missing an operand"),
};
let rhs = match &nodes[start..end][operator + 1] {
Node::Number(n) => n,
_ => panic!("operator is missing an operand"),
};
let number = (lhs * rhs).complete(PREC);
nodes.remove(operator - 1);
nodes.remove(operator - 1);
end -= 2;
nodes[operator - 1] = Node::Number(number);
}
while let Some(operator) = nodes[start..end]
.iter()
.position(|n| *n == Node::Operator(Operator::Div))
{
let lhs = match &nodes[start..end][operator - 1] {
Node::Number(n) => n,
_ => panic!("operator is missing an operand"),
};
let rhs = match &nodes[start..end][operator + 1] {
Node::Number(n) => n,
_ => panic!("operator is missing an operand"),
};
let number = (lhs / rhs).complete(PREC);
nodes.remove(operator - 1);
nodes.remove(operator - 1);
end -= 2;
nodes[operator - 1] = Node::Number(number);
}
while let Some(operator) = nodes[start..end]
.iter()
.position(|n| *n == Node::Operator(Operator::Plus))
{
let lhs = match &nodes[start..end][operator - 1] {
Node::Number(n) => n,
_ => panic!("operator is missing an operand"),
};
let rhs = match &nodes[start..end][operator + 1] {
Node::Number(n) => n,
_ => panic!("operator is missing an operand"),
};
let number = (lhs + rhs).complete(PREC);
nodes.remove(operator - 1);
nodes.remove(operator - 1);
end -= 2;
nodes[operator - 1] = Node::Number(number);
}
while let Some(operator) = nodes[start..end]
.iter()
.position(|n| *n == Node::Operator(Operator::Minus))
{
let lhs = match &nodes[start..end][operator - 1] {
Node::Number(n) => n,
_ => panic!("operator is missing an operand"),
};
let rhs = match &nodes[start..end][operator + 1] {
Node::Number(n) => n,
_ => panic!("operator is missing an operand"),
};
let number = (lhs - rhs).complete(PREC);
nodes.remove(operator - 1);
nodes.remove(operator - 1);
end -= 2;
nodes[operator - 1] = Node::Number(number);
}
if nodes.len() > 1 {
nodes.remove(end);
nodes.remove(start);
}
}
fn nodes_to_num(mut nodes: Vec<Node>) -> Float {
while let Some(end) = nodes.iter().position(|n| *n == Node::ParenthesisEnd) {
collapse_toplevel(&mut nodes, end);
}
let len = nodes.len();
collapse_toplevel(&mut nodes, len);
match nodes.pop().unwrap() {
Node::Number(n) => n,
_ => panic!("failed to collapse nodes: {nodes:?}"),
}
}
#[test]
fn test_nodes_to_num() {
assert_eq!(
nodes_to_num(vec![
Node::Function(Function::Sine),
Node::ParenthesisStart,
Node::Number(Float::with_val(PREC, 2)),
Node::ParenthesisEnd,
Node::Operator(Operator::Plus),
Node::Number(Float::with_val(PREC, 1))
])
.to_f64_round(rug::float::Round::Nearest),
1.9092974268256817,
);
}
#[test] #[test]
fn test_nodes_from_str() { fn test_nodes_from_str() {
assert_eq!( assert_eq!(