diff --git a/src/parse.rs b/src/parse.rs index 530bd6f..4088adf 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -1,7 +1,11 @@ #![allow(dead_code)] use std::str::FromStr; -use rug::{Float, float::ParseFloatError, ops::CompleteRound}; +use rug::{ + Float, + float::ParseFloatError, + ops::{CompleteRound, Pow}, +}; #[derive(Clone, Debug, thiserror::Error)] enum Error { @@ -28,6 +32,9 @@ enum Node { enum Operator { Plus, Minus, + Mult, + Div, + Exp, } impl TryFrom for Operator { type Error = (); @@ -35,6 +42,9 @@ impl TryFrom for Operator { match value { '+' => Ok(Self::Plus), '-' => Ok(Self::Minus), + '*' => Ok(Self::Mult), + '/' => Ok(Self::Div), + '^' => Ok(Self::Exp), _ => Err(()), } } @@ -148,6 +158,177 @@ fn nodes_from_str(s: &str) -> Result, Error> { Ok(nodes) } +fn collapse_toplevel(nodes: &mut Vec, 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) -> 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] fn test_nodes_from_str() { assert_eq!(