feat: nodes to num
co-authored by electria
This commit is contained in:
parent
e27438a244
commit
06aaf8cb8a
1 changed files with 182 additions and 1 deletions
183
src/parse.rs
183
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<char> for Operator {
|
||||
type Error = ();
|
||||
|
|
@ -35,6 +42,9 @@ impl TryFrom<char> 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<Vec<Node>, Error> {
|
|||
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]
|
||||
fn test_nodes_from_str() {
|
||||
assert_eq!(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue