From d84f2f70768420ea90078c5617f4156dde0cd21e Mon Sep 17 00:00:00 2001 From: Austen Adler Date: Mon, 31 May 2021 15:37:55 -0400 Subject: [PATCH] Add ArithmeticOperation --- src/calc.rs | 83 +++++++-------- src/calc/entries.rs | 236 ++++++++++++++++++++++++++++++----------- src/calc/operations.rs | 15 +-- 3 files changed, 223 insertions(+), 111 deletions(-) diff --git a/src/calc.rs b/src/calc.rs index 020ac9e..04a4c4c 100644 --- a/src/calc.rs +++ b/src/calc.rs @@ -7,7 +7,7 @@ use crate::calc::entries::CalculatorEntry; use confy::{load, store}; use entries::{Entry, Number}; use errors::{CalculatorError, CalculatorResult}; -use operations::{CalculatorOperation, CalculatorStateChange, MacroState, OpArgs}; +use operations::{ArithmeticOperation,CalculatorOperation, CalculatorStateChange, MacroState, OpArgs}; use serde::ser::Serializer; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashMap}; @@ -214,29 +214,29 @@ impl Calculator { _ => Err(CalculatorError::ParseError), } } - '+' => self.op(CalculatorOperation::Add), - '-' => self.op(CalculatorOperation::Subtract), - '*' => self.op(CalculatorOperation::Multiply), - '/' => self.op(CalculatorOperation::Divide), - 'n' => self.op(CalculatorOperation::Negate), - '|' => self.op(CalculatorOperation::AbsoluteValue), - 'i' => self.op(CalculatorOperation::Inverse), - '%' => self.op(CalculatorOperation::Modulo), + '+' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Add)), + '-' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Subtract)), + '*' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Multiply)), + '/' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide)), + 'n' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate)), + '|' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::AbsoluteValue)), + 'i' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse)), + '%' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Modulo)), + '?' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::IntegerDivide)), + 's' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Sin)), + 'c' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Cos)), + 't' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Tan)), + 'S' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ASin)), + 'C' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ACos)), + 'T' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ATan)), + 'v' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Sqrt)), + '^' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Pow)), + 'l' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Log)), + 'L' => self.op(CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Ln)), + // Special '\\' => self.op(CalculatorOperation::Drop), - '?' => self.op(CalculatorOperation::IntegerDivide), ' ' => self.op(CalculatorOperation::Dup), '>' => self.op(CalculatorOperation::Swap), - 's' => self.op(CalculatorOperation::Sin), - 'c' => self.op(CalculatorOperation::Cos), - 't' => self.op(CalculatorOperation::Tan), - 'S' => self.op(CalculatorOperation::ASin), - 'C' => self.op(CalculatorOperation::ACos), - 'T' => self.op(CalculatorOperation::ATan), - 'v' => self.op(CalculatorOperation::Sqrt), - '^' => self.op(CalculatorOperation::Pow), - 'l' => self.op(CalculatorOperation::Log), - 'L' => self.op(CalculatorOperation::Ln), - // Special 'u' => self.op(CalculatorOperation::Undo), 'U' => self.op(CalculatorOperation::Redo), // State modifiers @@ -478,7 +478,7 @@ impl Calculator { let entry = self.peek(0)?; let f = match entry { Entry::Number(Number { value }) => value, - // Entry::Vector(_) => return Err(CalculatorError::TypeMismatch), + Entry::Vector(_) => return Err(CalculatorError::TypeMismatch), }; // Ensure this can be cast to a usize if !f.is_finite() || f.is_sign_negative() { @@ -507,63 +507,63 @@ impl Calculator { } } let state_change = match op { - CalculatorOperation::Add => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Add) => { self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.add(a)?))) } - CalculatorOperation::Subtract => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Subtract) => { self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.sub(a)?))) } - CalculatorOperation::Multiply => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Multiply) => { self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.mul(a)?))) } - CalculatorOperation::Divide => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide) => { self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(a)?))) } - CalculatorOperation::IntegerDivide => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::IntegerDivide) => { self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(a)?))) } - CalculatorOperation::Negate => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate) => { self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?))) } - CalculatorOperation::AbsoluteValue => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::AbsoluteValue) => { self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?))) } - CalculatorOperation::Inverse => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse) => { self.unary_op(|a| Ok(OpArgs::Unary(a.inverse()?))) } - CalculatorOperation::Modulo => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Modulo) => { self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.modulo(a)?))) } - CalculatorOperation::Sin => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Sin) => { let angle_mode = self.angle_mode; self.unary_op(|a| Ok(OpArgs::Unary(a.sin(angle_mode)?))) } - CalculatorOperation::Cos => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Cos) => { let angle_mode = self.angle_mode; self.unary_op(|a| Ok(OpArgs::Unary(a.cos(angle_mode)?))) } - CalculatorOperation::Tan => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Tan) => { let angle_mode = self.angle_mode; self.unary_op(|a| Ok(OpArgs::Unary(a.tan(angle_mode)?))) } - CalculatorOperation::ASin => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ASin) => { let angle_mode = self.angle_mode; self.unary_op(|a| Ok(OpArgs::Unary(a.asin(angle_mode)?))) } - CalculatorOperation::ACos => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ACos) => { let angle_mode = self.angle_mode; self.unary_op(|a| Ok(OpArgs::Unary(a.acos(angle_mode)?))) } - CalculatorOperation::ATan => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::ATan) => { let angle_mode = self.angle_mode; self.unary_op(|a| Ok(OpArgs::Unary(a.atan(angle_mode)?))) } - CalculatorOperation::Sqrt => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Sqrt) => { self.unary_op(|a| Ok(OpArgs::Unary(a.sqrt()?))) } - CalculatorOperation::Log => self.unary_op(|a| Ok(OpArgs::Unary(a.log()?))), - CalculatorOperation::Ln => self.unary_op(|a| Ok(OpArgs::Unary(a.ln()?))), - CalculatorOperation::Pow => { + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Log) => self.unary_op(|a| Ok(OpArgs::Unary(a.log()?))), + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Ln) => self.unary_op(|a| Ok(OpArgs::Unary(a.ln()?))), + CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Pow) => { self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(a)?))) } CalculatorOperation::Dup => { @@ -741,7 +741,6 @@ impl Calculator { &mut self, op: impl FnOnce(Entry) -> CalculatorResult, ) -> CalculatorResult { - // TODO: Use peek instead of stack.get() let arg = self.peek(0)?; Ok(CalculatorStateChange { pop: OpArgs::Unary(arg.clone()), diff --git a/src/calc/entries.rs b/src/calc/entries.rs index 4fde277..9a294a0 100644 --- a/src/calc/entries.rs +++ b/src/calc/entries.rs @@ -1,5 +1,6 @@ // use super::operations::CalculatorStateChange; -use super::errors::CalculatorResult; +// TODO: This file kina blows. Tons of repetition. Do not know how to fix yet though +use super::errors::{CalculatorError, CalculatorResult}; use super::types::CalculatorAngleMode; use crate::calc::CalculatorDisplayMode; use serde::{Deserialize, Serialize}; @@ -11,6 +12,15 @@ pub struct Number { pub value: f64, } +impl Number { + fn binary_op(arg: &Entry, op: impl Fn(&Number) -> Number) -> CalculatorResult { + match arg { + Entry::Number(number) => Ok(Entry::Number(op(number))), + Entry::Vector(vector) => Ok(vector.map_into(op)), + } + } +} + impl PartialEq for Number { fn eq(&self, other: &Self) -> bool { if self.value.is_nan() && other.value.is_nan() @@ -29,17 +39,52 @@ impl PartialEq for Number { } } -// #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] -// pub struct Vector { -// pub value: Vec, -// } +#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct Vector { + pub direction: bool, + pub values: Vec, +} + +impl Vector { + fn binary_op( + &self, + arg: &Entry, + op: impl Fn((&Number, &Number)) -> Number, + ) -> CalculatorResult { + match arg { + // Entry::Number(number) => Ok(Entry::Number(op(number))), + Entry::Number(number) => Ok(self.map_into(|t| op((t, number)))), + Entry::Vector(vector) => { + if self.values.len() != vector.values.len() { + return Err(CalculatorError::ArithmeticError); + } + + Ok(Entry::Vector(Vector { + values: self + .values + .iter() + .zip(vector.values.iter()) + .map(op) + .collect(), + ..*self + })) + } + } + } + + pub fn map_into(&self, op: impl Fn(&Number) -> Number) -> Entry { + Entry::Vector(Vector { + values: (self.values.iter().map(op).collect()), + ..*self + }) + } +} -// TODO: Remove the copy trait #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] #[serde(tag = "type")] pub enum Entry { Number(Number), - // Vector(Vec), + Vector(Vector), // Matrix(Vec>), } @@ -47,127 +92,127 @@ impl CalculatorEntry for Entry { fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String { match self { Self::Number(number) => number.format_entry(display_mode), - // Self::Vector(vector) => vector.add(), + Self::Vector(vector) => vector.format_entry(display_mode), } } fn is_valid(&self) -> bool { match self { Self::Number(number) => number.is_valid(), - // Self::Vector(vector) => vector.add(), + Self::Vector(vector) => vector.is_valid(), } } fn add(&self, arg: Self) -> CalculatorResult { match self { Self::Number(number) => number.add(arg), - // Self::Vector(vector) => vector.add(), + Self::Vector(vector) => vector.add(arg), } } fn sub(&self, arg: Self) -> CalculatorResult { match self { Self::Number(number) => number.sub(arg), - // Self::Vector(vector) => vector.sub(), + Self::Vector(vector) => vector.sub(arg), } } fn mul(&self, arg: Self) -> CalculatorResult { match self { Self::Number(number) => number.mul(arg), - // Self::Vector(vector) => vector.mul(), + Self::Vector(vector) => vector.mul(arg), } } fn div(&self, arg: Self) -> CalculatorResult { match self { Self::Number(number) => number.div(arg), - // Self::Vector(vector) => vector.div(), + Self::Vector(vector) => vector.div(arg), } } fn int_divide(&self, arg: Self) -> CalculatorResult { match self { Self::Number(number) => number.int_divide(arg), - // Self::Vector(vector) => vector.int_divide(), + Self::Vector(vector) => vector.int_divide(arg), } } fn negate(&self) -> CalculatorResult { match self { Self::Number(number) => number.negate(), - // Self::Vector(vector) => vector.negate(), + Self::Vector(vector) => vector.negate(), } } fn abs(&self) -> CalculatorResult { match self { Self::Number(number) => number.abs(), - // Self::Vector(vector) => vector.abs(), + Self::Vector(vector) => vector.abs(), } } fn inverse(&self) -> CalculatorResult { match self { Self::Number(number) => number.inverse(), - // Self::Vector(vector) => vector.inverse(), + Self::Vector(vector) => vector.inverse(), } } fn modulo(&self, arg: Self) -> CalculatorResult { match self { Self::Number(number) => number.modulo(arg), - // Self::Vector(vector) => vector.modulo(), + Self::Vector(vector) => vector.modulo(arg), } } fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult { match self { Self::Number(number) => number.sin(angle_mode), - // Self::Vector(vector) => vector.sin(), + Self::Vector(vector) => vector.sin(angle_mode), } } fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult { match self { Self::Number(number) => number.cos(angle_mode), - // Self::Vector(vector) => vector.cos(), + Self::Vector(vector) => vector.cos(angle_mode), } } fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult { match self { Self::Number(number) => number.tan(angle_mode), - // Self::Vector(vector) => vector.tan(), + Self::Vector(vector) => vector.tan(angle_mode), } } fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult { match self { Self::Number(number) => number.asin(angle_mode), - // Self::Vector(vector) => vector.asin(), + Self::Vector(vector) => vector.asin(angle_mode), } } fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult { match self { Self::Number(number) => number.acos(angle_mode), - // Self::Vector(vector) => vector.acos(), + Self::Vector(vector) => vector.acos(angle_mode), } } fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult { match self { Self::Number(number) => number.atan(angle_mode), - // Self::Vector(vector) => vector.atan(), + Self::Vector(vector) => vector.atan(angle_mode), } } fn sqrt(&self) -> CalculatorResult { match self { Self::Number(number) => number.sqrt(), - // Self::Vector(vector) => vector.sqrt(), + Self::Vector(vector) => vector.sqrt(), } } fn log(&self) -> CalculatorResult { match self { Self::Number(number) => number.log(), - // Self::Vector(vector) => vector.log(), + Self::Vector(vector) => vector.log(), } } fn ln(&self) -> CalculatorResult { match self { Self::Number(number) => number.ln(), - // Self::Vector(vector) => vector.ln(), + Self::Vector(vector) => vector.ln(), } } fn pow(&self, arg: Self) -> CalculatorResult { match self { Self::Number(number) => number.pow(arg), - // Self::Vector(vector) => vector.pow(), + Self::Vector(vector) => vector.pow(arg), } } } @@ -194,39 +239,29 @@ impl CalculatorEntry for Number { !self.value.is_nan() && !self.value.is_infinite() } fn add(&self, arg: Entry) -> CalculatorResult { - match arg { - Entry::Number(Self { value }) => Ok(Entry::Number(Self { - value: value + self.value, - })), - } + Number::binary_op(&arg, |b| Self { + value: b.value + self.value, + }) } fn sub(&self, arg: Entry) -> CalculatorResult { - match arg { - Entry::Number(Self { value }) => Ok(Entry::Number(Self { - value: value - self.value, - })), - } + Number::binary_op(&arg, |b| Self { + value: b.value - self.value, + }) } fn mul(&self, arg: Entry) -> CalculatorResult { - match arg { - Entry::Number(Self { value }) => Ok(Entry::Number(Self { - value: value * self.value, - })), - } + Number::binary_op(&arg, |b| Self { + value: b.value * self.value, + }) } fn div(&self, arg: Entry) -> CalculatorResult { - match arg { - Entry::Number(Self { value }) => Ok(Entry::Number(Self { - value: value / self.value, - })), - } + Number::binary_op(&arg, |b| Self { + value: b.value / self.value, + }) } fn int_divide(&self, arg: Entry) -> CalculatorResult { - match arg { - Entry::Number(Self { value }) => Ok(Entry::Number(Self { - value: value.div_euclid(self.value), - })), - } + Number::binary_op(&arg, |b| Self { + value: b.value.div_euclid(self.value), + }) } fn negate(&self) -> CalculatorResult { Ok(Entry::Number(Self { value: -self.value })) @@ -242,11 +277,9 @@ impl CalculatorEntry for Number { })) } fn modulo(&self, arg: Entry) -> CalculatorResult { - match arg { - Entry::Number(Self { value }) => Ok(Entry::Number(Self { - value: value % self.value, - })), - } + Number::binary_op(&arg, |b| Self { + value: b.value % self.value, + }) } fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult { Ok(Entry::Number(Self { @@ -330,11 +363,88 @@ impl CalculatorEntry for Number { })) } fn pow(&self, arg: Entry) -> CalculatorResult { - match arg { - Entry::Number(Self { value }) => Ok(Entry::Number(Self { - value: value.powf(self.value), - })), - } + Number::binary_op(&arg, |b| Self { + value: b.value.powf(self.value), + }) + } +} + +impl CalculatorEntry for Vector { + // Misc + fn is_valid(&self) -> bool { + !self.values + .iter() + .find(|number| !number.is_valid()) + .is_some() + } + fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String { + format!( + "[{}]", + self.values + .iter() + .map(|number| number.format_entry(display_mode)) + .collect::>() + .join("; ") + ) + } + // Mathematical operations + fn add(&self, arg: Entry) -> CalculatorResult { + self.binary_op(&arg, |(a, b)| Number { + value: b.value + a.value, + }) + } + fn sub(&self, arg: Entry) -> CalculatorResult { + self.binary_op(&arg, |(a, b)| Number { + value: b.value - a.value, + }) + } + fn mul(&self, arg: Entry) -> CalculatorResult { + self.binary_op(&arg, |(a, b)| Number { + value: b.value * a.value, + }) + } + fn div(&self, arg: Entry) -> CalculatorResult { + self.binary_op(&arg, |(a, b)| Number { + value: b.value / a.value, + }) + } + fn int_divide(&self, arg: Entry) -> CalculatorResult { + self.binary_op(&arg, |(a, b)| Number { + value: b.value.div_euclid(a.value), + }) + } + fn negate(&self) -> CalculatorResult { + Ok(self.map_into(|n| Number { value: -n.value })) + } + fn abs(&self) -> CalculatorResult { + Ok(self.map_into(|n| Number { + value: n.value.abs(), + })) + } + fn inverse(&self) -> CalculatorResult { + Ok(Entry::Vector(Vector { + direction: !self.direction, + ..*self + })) + } + fn modulo(&self, arg: Entry) -> CalculatorResult { + self.binary_op(&arg, |(a, b)| Number { + value: b.value % a.value, + }) + } + fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult {} + fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult {} + fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult {} + fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult {} + fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult {} + fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult {} + fn sqrt(&self) -> CalculatorResult {} + fn log(&self) -> CalculatorResult {} + fn ln(&self) -> CalculatorResult {} + fn pow(&self, arg: Entry) -> CalculatorResult { + self.binary_op(&arg, |(a, b)| Number { + value: b.value.powf(a.value), + }) } } diff --git a/src/calc/operations.rs b/src/calc/operations.rs index 4daff68..3161b07 100644 --- a/src/calc/operations.rs +++ b/src/calc/operations.rs @@ -1,8 +1,8 @@ use super::entries::Entry; use serde::{Deserialize, Serialize}; -/// Operations that can be sent to the calculator such as +, -, or undo + #[derive(PartialEq, Debug, Serialize, Deserialize)] -pub enum CalculatorOperation { +pub enum ArithmeticOperation { Add, Subtract, Multiply, @@ -12,7 +12,6 @@ pub enum CalculatorOperation { Inverse, Modulo, IntegerDivide, - //Remainder, Sin, Cos, Tan, @@ -20,12 +19,16 @@ pub enum CalculatorOperation { ACos, ATan, Sqrt, - Undo, - Redo, Pow, - // Factorial, Log, Ln, +} +/// Operations that can be sent to the calculator such as +, -, or undo +#[derive(PartialEq, Debug, Serialize, Deserialize)] +pub enum CalculatorOperation { + ArithmeticOperation(ArithmeticOperation), + Undo, + Redo, Drop, Dup, Swap,