Cleanup numeric entries

This commit is contained in:
Austen Adler 2021-05-30 23:10:11 -04:00
parent dab0333b31
commit 39e3c83abc
2 changed files with 664 additions and 621 deletions

View File

@ -14,8 +14,8 @@ use std::collections::{BTreeMap, HashMap};
use std::collections::{HashSet, VecDeque}; use std::collections::{HashSet, VecDeque};
use types::{ use types::{
CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants, CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants,
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters, CalculatorState, CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters,
RegisterState, CalculatorState, RegisterState,
}; };
/// The maximum precision allowed for the calculator /// The maximum precision allowed for the calculator
@ -186,7 +186,8 @@ impl Calculator {
} }
fn normal_input(&mut self, c: char) -> CalculatorResult<()> { fn normal_input(&mut self, c: char) -> CalculatorResult<()> {
match c { match c {
c @ '0'..='9' | c @ '.' | c @ 'e' => match c { c @ '0'..='9' | c @ '.' | c @ 'e' => {
match c {
'0'..='9' => { '0'..='9' => {
self.l.push(c); self.l.push(c);
Ok(()) Ok(())
@ -211,7 +212,8 @@ impl Calculator {
Ok(()) Ok(())
} }
_ => Err(CalculatorError::ParseError), _ => Err(CalculatorError::ParseError),
}, }
}
'+' => self.op(CalculatorOperation::Add), '+' => self.op(CalculatorOperation::Add),
'-' => self.op(CalculatorOperation::Subtract), '-' => self.op(CalculatorOperation::Subtract),
'*' => self.op(CalculatorOperation::Multiply), '*' => self.op(CalculatorOperation::Multiply),
@ -243,11 +245,13 @@ impl Calculator {
Ok(()) Ok(())
} }
'r' => { 'r' => {
self.state = CalculatorState::WaitingForRegister(RegisterState::Load); self.state =
CalculatorState::WaitingForRegister(RegisterState::Load);
Ok(()) Ok(())
} }
'R' => { 'R' => {
self.state = CalculatorState::WaitingForRegister(RegisterState::Save); self.state =
CalculatorState::WaitingForRegister(RegisterState::Save);
Ok(()) Ok(())
} }
'`' => { '`' => {
@ -306,7 +310,11 @@ impl Calculator {
Ok(()) Ok(())
} }
fn register_input(&mut self, register_state: RegisterState, c: char) -> CalculatorResult<()> { fn register_input(
&mut self,
register_state: RegisterState,
c: char,
) -> CalculatorResult<()> {
match register_state { match register_state {
RegisterState::Save => { RegisterState::Save => {
let f = self.pop()?; let f = self.pop()?;
@ -333,8 +341,14 @@ impl Calculator {
'r' => self.angle_mode = CalculatorAngleMode::Radians, 'r' => self.angle_mode = CalculatorAngleMode::Radians,
'g' => self.angle_mode = CalculatorAngleMode::Grads, 'g' => self.angle_mode = CalculatorAngleMode::Grads,
'_' => self.display_mode = CalculatorDisplayMode::Default, '_' => self.display_mode = CalculatorDisplayMode::Default,
',' => self.display_mode = CalculatorDisplayMode::Separated { separator: ',' }, ',' => {
' ' => self.display_mode = CalculatorDisplayMode::Separated { separator: ' ' }, self.display_mode =
CalculatorDisplayMode::Separated { separator: ',' }
}
' ' => {
self.display_mode =
CalculatorDisplayMode::Separated { separator: ' ' }
}
's' => { 's' => {
self.display_mode = CalculatorDisplayMode::Scientific { self.display_mode = CalculatorDisplayMode::Scientific {
precision: DEFAULT_PRECISION, precision: DEFAULT_PRECISION,
@ -493,17 +507,33 @@ impl Calculator {
} }
} }
let state_change = match op { let state_change = match op {
CalculatorOperation::Add => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.add(a)?))), CalculatorOperation::Add => {
CalculatorOperation::Subtract => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.sub(a)?))), self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.add(a)?)))
CalculatorOperation::Multiply => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.mul(a)?))), }
CalculatorOperation::Divide => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(a)?))), CalculatorOperation::Subtract => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.sub(a)?)))
}
CalculatorOperation::Multiply => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.mul(a)?)))
}
CalculatorOperation::Divide => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(a)?)))
}
CalculatorOperation::IntegerDivide => { CalculatorOperation::IntegerDivide => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(a)?))) self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(a)?)))
} }
CalculatorOperation::Negate => self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?))), CalculatorOperation::Negate => {
CalculatorOperation::AbsoluteValue => self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?))), self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?)))
CalculatorOperation::Inverse => self.unary_op(|a| Ok(OpArgs::Unary(a.inverse()?))), }
CalculatorOperation::Modulo => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.modulo(a)?))), CalculatorOperation::AbsoluteValue => {
self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?)))
}
CalculatorOperation::Inverse => {
self.unary_op(|a| Ok(OpArgs::Unary(a.inverse()?)))
}
CalculatorOperation::Modulo => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.modulo(a)?)))
}
CalculatorOperation::Sin => { CalculatorOperation::Sin => {
let angle_mode = self.angle_mode; let angle_mode = self.angle_mode;
self.unary_op(|a| Ok(OpArgs::Unary(a.sin(angle_mode)?))) self.unary_op(|a| Ok(OpArgs::Unary(a.sin(angle_mode)?)))
@ -528,13 +558,21 @@ impl Calculator {
let angle_mode = self.angle_mode; let angle_mode = self.angle_mode;
self.unary_op(|a| Ok(OpArgs::Unary(a.atan(angle_mode)?))) self.unary_op(|a| Ok(OpArgs::Unary(a.atan(angle_mode)?)))
} }
CalculatorOperation::Sqrt => self.unary_op(|a| Ok(OpArgs::Unary(a.sqrt()?))), CalculatorOperation::Sqrt => {
self.unary_op(|a| Ok(OpArgs::Unary(a.sqrt()?)))
}
CalculatorOperation::Log => self.unary_op(|a| Ok(OpArgs::Unary(a.log()?))), CalculatorOperation::Log => self.unary_op(|a| Ok(OpArgs::Unary(a.log()?))),
CalculatorOperation::Ln => self.unary_op(|a| Ok(OpArgs::Unary(a.ln()?))), CalculatorOperation::Ln => self.unary_op(|a| Ok(OpArgs::Unary(a.ln()?))),
CalculatorOperation::Pow => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(a)?))), CalculatorOperation::Pow => {
CalculatorOperation::Dup => self.unary_op(|a| Ok(OpArgs::Binary([a, a]))), self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(a)?)))
}
CalculatorOperation::Dup => {
self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a])))
}
CalculatorOperation::Drop => self.unary_op(|_| Ok(OpArgs::None)), CalculatorOperation::Drop => self.unary_op(|_| Ok(OpArgs::None)),
CalculatorOperation::Swap => self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a]))), CalculatorOperation::Swap => {
self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a])))
}
CalculatorOperation::Undo => return self.history_op(false), CalculatorOperation::Undo => return self.history_op(false),
CalculatorOperation::Redo => return self.history_op(true), CalculatorOperation::Redo => return self.history_op(true),
// Macros are a no-op operator; need to insert for undo/redo // Macros are a no-op operator; need to insert for undo/redo
@ -565,7 +603,11 @@ impl Calculator {
} }
.last() .last()
.ok_or_else(|| { .ok_or_else(|| {
CalculatorError::EmptyHistory(String::from(if forward { "redo" } else { "undo" })) CalculatorError::EmptyHistory(String::from(if forward {
"redo"
} else {
"undo"
}))
})?; })?;
let target_history_mode = if forward { let target_history_mode = if forward {
@ -648,12 +690,12 @@ impl Calculator {
match to_pop { match to_pop {
OpArgs::Unary(a) => { OpArgs::Unary(a) => {
self.stack_eq(0, *a)?; self.stack_eq(0, a)?;
self.stack.pop_front(); self.stack.pop_front();
} }
OpArgs::Binary([a, b]) => { OpArgs::Binary([a, b]) => {
self.stack_eq(0, *a)?; self.stack_eq(0, a)?;
self.stack_eq(1, *b)?; self.stack_eq(1, b)?;
self.stack.pop_front(); self.stack.pop_front();
self.stack.pop_front(); self.stack.pop_front();
} }
@ -662,11 +704,11 @@ impl Calculator {
match to_push { match to_push {
OpArgs::Unary(a) => { OpArgs::Unary(a) => {
self.stack.push_front(*a); self.stack.push_front(a.clone()); // TODO: Remove the clones
} }
OpArgs::Binary([a, b]) => { OpArgs::Binary([a, b]) => {
self.stack.push_front(*b); self.stack.push_front(b.clone()); // TODO: Remove the clones
self.stack.push_front(*a); self.stack.push_front(a.clone()); // TODO: Remove the clones
} }
OpArgs::Macro(_) | OpArgs::None => {} OpArgs::Macro(_) | OpArgs::None => {}
}; };
@ -681,8 +723,8 @@ impl Calculator {
} }
/// Checks if a value on the stack is equal to a given value /// Checks if a value on the stack is equal to a given value
fn stack_eq(&mut self, idx: usize, value: Entry) -> CalculatorResult<()> { fn stack_eq(&mut self, idx: usize, value: &Entry) -> CalculatorResult<()> {
if self.peek(idx)? == value { if self.peek(idx)? == *value {
Err(CalculatorError::CorruptStateChange(format!( Err(CalculatorError::CorruptStateChange(format!(
"Stack index {} should be {}, but is {}", "Stack index {} should be {}, but is {}",
idx, idx,
@ -702,7 +744,7 @@ impl Calculator {
// TODO: Use peek instead of stack.get() // TODO: Use peek instead of stack.get()
let arg = self.peek(0)?; let arg = self.peek(0)?;
Ok(CalculatorStateChange { Ok(CalculatorStateChange {
pop: OpArgs::Unary(arg), pop: OpArgs::Unary(arg.clone()),
push: op(arg)?, push: op(arg)?,
}) })
} }
@ -713,7 +755,7 @@ impl Calculator {
) -> CalculatorResult<CalculatorStateChange> { ) -> CalculatorResult<CalculatorStateChange> {
let args: [Entry; 2] = [self.peek(0)?, self.peek(1)?]; let args: [Entry; 2] = [self.peek(0)?, self.peek(1)?];
Ok(CalculatorStateChange { Ok(CalculatorStateChange {
pop: OpArgs::Binary(args), pop: OpArgs::Binary(args.clone()),
push: op(args)?, push: op(args)?,
}) })
} }

View File

@ -34,6 +34,7 @@ impl PartialEq for Number {
// pub value: Vec<Number>, // pub value: Vec<Number>,
// } // }
// TODO: Remove the copy trait
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum Entry { pub enum Entry {
@ -194,61 +195,61 @@ impl CalculatorEntry for Number {
} }
fn add(&self, arg: Entry) -> CalculatorResult<Entry> { fn add(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg { match arg {
Entry::Number(Number { value }) => Ok(Entry::Number(Number { Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value + self.value, value: value + self.value,
})), })),
} }
} }
fn sub(&self, arg: Entry) -> CalculatorResult<Entry> { fn sub(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg { match arg {
Entry::Number(Number { value }) => Ok(Entry::Number(Number { Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value - self.value, value: value - self.value,
})), })),
} }
} }
fn mul(&self, arg: Entry) -> CalculatorResult<Entry> { fn mul(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg { match arg {
Entry::Number(Number { value }) => Ok(Entry::Number(Number { Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value * self.value, value: value * self.value,
})), })),
} }
} }
fn div(&self, arg: Entry) -> CalculatorResult<Entry> { fn div(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg { match arg {
Entry::Number(Number { value }) => Ok(Entry::Number(Number { Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value / self.value, value: value / self.value,
})), })),
} }
} }
fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry> { fn int_divide(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg { match arg {
Entry::Number(Number { value }) => Ok(Entry::Number(Number { Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value.div_euclid(self.value), value: value.div_euclid(self.value),
})), })),
} }
} }
fn negate(&self) -> CalculatorResult<Entry> { fn negate(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { value: -self.value })) Ok(Entry::Number(Self { value: -self.value }))
} }
fn abs(&self) -> CalculatorResult<Entry> { fn abs(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: self.value.abs(), value: self.value.abs(),
})) }))
} }
fn inverse(&self) -> CalculatorResult<Entry> { fn inverse(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: self.value.recip(), value: self.value.recip(),
})) }))
} }
fn modulo(&self, arg: Entry) -> CalculatorResult<Entry> { fn modulo(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg { match arg {
Entry::Number(Number { value }) => Ok(Entry::Number(Number { Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value % self.value, value: value % self.value,
})), })),
} }
} }
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> { fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: match angle_mode { value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.to_radians().sin(), CalculatorAngleMode::Degrees => self.value.to_radians().sin(),
CalculatorAngleMode::Radians => self.value.sin(), CalculatorAngleMode::Radians => self.value.sin(),
@ -259,7 +260,7 @@ impl CalculatorEntry for Number {
})) }))
} }
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> { fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: match angle_mode { value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.to_radians().cos(), CalculatorAngleMode::Degrees => self.value.to_radians().cos(),
CalculatorAngleMode::Radians => self.value.cos(), CalculatorAngleMode::Radians => self.value.cos(),
@ -270,7 +271,7 @@ impl CalculatorEntry for Number {
})) }))
} }
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> { fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: match angle_mode { value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.to_radians().tan(), CalculatorAngleMode::Degrees => self.value.to_radians().tan(),
CalculatorAngleMode::Radians => self.value.tan(), CalculatorAngleMode::Radians => self.value.tan(),
@ -281,7 +282,7 @@ impl CalculatorEntry for Number {
})) }))
} }
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> { fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: match angle_mode { value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.asin().to_degrees(), CalculatorAngleMode::Degrees => self.value.asin().to_degrees(),
CalculatorAngleMode::Radians => self.value.asin(), CalculatorAngleMode::Radians => self.value.asin(),
@ -292,7 +293,7 @@ impl CalculatorEntry for Number {
})) }))
} }
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> { fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: match angle_mode { value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.acos().to_degrees(), CalculatorAngleMode::Degrees => self.value.acos().to_degrees(),
CalculatorAngleMode::Radians => self.value.acos(), CalculatorAngleMode::Radians => self.value.acos(),
@ -303,7 +304,7 @@ impl CalculatorEntry for Number {
})) }))
} }
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> { fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: match angle_mode { value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.atan().to_degrees(), CalculatorAngleMode::Degrees => self.value.atan().to_degrees(),
CalculatorAngleMode::Radians => self.value.atan(), CalculatorAngleMode::Radians => self.value.atan(),
@ -314,23 +315,23 @@ impl CalculatorEntry for Number {
})) }))
} }
fn sqrt(&self) -> CalculatorResult<Entry> { fn sqrt(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: self.value.sqrt(), value: self.value.sqrt(),
})) }))
} }
fn log(&self) -> CalculatorResult<Entry> { fn log(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: self.value.log10(), value: self.value.log10(),
})) }))
} }
fn ln(&self) -> CalculatorResult<Entry> { fn ln(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Number { Ok(Entry::Number(Self {
value: self.value.ln(), value: self.value.ln(),
})) }))
} }
fn pow(&self, arg: Entry) -> CalculatorResult<Entry> { fn pow(&self, arg: Entry) -> CalculatorResult<Entry> {
match arg { match arg {
Entry::Number(Number { value }) => Ok(Entry::Number(Number { Entry::Number(Self { value }) => Ok(Entry::Number(Self {
value: value.powf(self.value), value: value.powf(self.value),
})), })),
} }