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 types::{
CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants,
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters, CalculatorState,
RegisterState,
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters,
CalculatorState, RegisterState,
};
/// The maximum precision allowed for the calculator
@ -186,7 +186,8 @@ impl Calculator {
}
fn normal_input(&mut self, c: char) -> CalculatorResult<()> {
match c {
c @ '0'..='9' | c @ '.' | c @ 'e' => match c {
c @ '0'..='9' | c @ '.' | c @ 'e' => {
match c {
'0'..='9' => {
self.l.push(c);
Ok(())
@ -211,7 +212,8 @@ impl Calculator {
Ok(())
}
_ => Err(CalculatorError::ParseError),
},
}
}
'+' => self.op(CalculatorOperation::Add),
'-' => self.op(CalculatorOperation::Subtract),
'*' => self.op(CalculatorOperation::Multiply),
@ -243,11 +245,13 @@ impl Calculator {
Ok(())
}
'r' => {
self.state = CalculatorState::WaitingForRegister(RegisterState::Load);
self.state =
CalculatorState::WaitingForRegister(RegisterState::Load);
Ok(())
}
'R' => {
self.state = CalculatorState::WaitingForRegister(RegisterState::Save);
self.state =
CalculatorState::WaitingForRegister(RegisterState::Save);
Ok(())
}
'`' => {
@ -306,7 +310,11 @@ impl Calculator {
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 {
RegisterState::Save => {
let f = self.pop()?;
@ -333,8 +341,14 @@ impl Calculator {
'r' => self.angle_mode = CalculatorAngleMode::Radians,
'g' => self.angle_mode = CalculatorAngleMode::Grads,
'_' => 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' => {
self.display_mode = CalculatorDisplayMode::Scientific {
precision: DEFAULT_PRECISION,
@ -493,17 +507,33 @@ impl Calculator {
}
}
let state_change = match op {
CalculatorOperation::Add => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.add(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::Add => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.add(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 => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(a)?)))
}
CalculatorOperation::Negate => self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?))),
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::Negate => {
self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?)))
}
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 => {
let angle_mode = self.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;
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::Ln => self.unary_op(|a| Ok(OpArgs::Unary(a.ln()?))),
CalculatorOperation::Pow => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(a)?))),
CalculatorOperation::Dup => self.unary_op(|a| Ok(OpArgs::Binary([a, a]))),
CalculatorOperation::Pow => {
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::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::Redo => return self.history_op(true),
// Macros are a no-op operator; need to insert for undo/redo
@ -565,7 +603,11 @@ impl Calculator {
}
.last()
.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 {
@ -648,12 +690,12 @@ impl Calculator {
match to_pop {
OpArgs::Unary(a) => {
self.stack_eq(0, *a)?;
self.stack_eq(0, a)?;
self.stack.pop_front();
}
OpArgs::Binary([a, b]) => {
self.stack_eq(0, *a)?;
self.stack_eq(1, *b)?;
self.stack_eq(0, a)?;
self.stack_eq(1, b)?;
self.stack.pop_front();
self.stack.pop_front();
}
@ -662,11 +704,11 @@ impl Calculator {
match to_push {
OpArgs::Unary(a) => {
self.stack.push_front(*a);
self.stack.push_front(a.clone()); // TODO: Remove the clones
}
OpArgs::Binary([a, b]) => {
self.stack.push_front(*b);
self.stack.push_front(*a);
self.stack.push_front(b.clone()); // TODO: Remove the clones
self.stack.push_front(a.clone()); // TODO: Remove the clones
}
OpArgs::Macro(_) | OpArgs::None => {}
};
@ -681,8 +723,8 @@ impl Calculator {
}
/// Checks if a value on the stack is equal to a given value
fn stack_eq(&mut self, idx: usize, value: Entry) -> CalculatorResult<()> {
if self.peek(idx)? == value {
fn stack_eq(&mut self, idx: usize, value: &Entry) -> CalculatorResult<()> {
if self.peek(idx)? == *value {
Err(CalculatorError::CorruptStateChange(format!(
"Stack index {} should be {}, but is {}",
idx,
@ -702,7 +744,7 @@ impl Calculator {
// TODO: Use peek instead of stack.get()
let arg = self.peek(0)?;
Ok(CalculatorStateChange {
pop: OpArgs::Unary(arg),
pop: OpArgs::Unary(arg.clone()),
push: op(arg)?,
})
}
@ -713,7 +755,7 @@ impl Calculator {
) -> CalculatorResult<CalculatorStateChange> {
let args: [Entry; 2] = [self.peek(0)?, self.peek(1)?];
Ok(CalculatorStateChange {
pop: OpArgs::Binary(args),
pop: OpArgs::Binary(args.clone()),
push: op(args)?,
})
}

View File

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