Get operations working with the calculator interface

This commit is contained in:
Austen Adler 2021-06-01 22:01:07 -04:00
parent e05b0726f1
commit 53891274f1
3 changed files with 1543 additions and 1427 deletions

View File

@ -5,7 +5,7 @@ pub mod types;
use crate::calc::entries::CalculatorEntry; use crate::calc::entries::CalculatorEntry;
use confy::{load, store}; use confy::{load, store};
use entries::{Entry, Number}; use entries::{Entry, Number, Vector};
use errors::{CalculatorError, CalculatorResult}; use errors::{CalculatorError, CalculatorResult};
use operations::{ use operations::{
ArithmeticOperation, CalculatorOperation, CalculatorStateChange, MacroState, OpArgs, ArithmeticOperation, CalculatorOperation, CalculatorStateChange, MacroState, OpArgs,
@ -16,8 +16,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
@ -269,6 +269,8 @@ impl Calculator {
'L' => self.op(CalculatorOperation::ArithmeticOperation( 'L' => self.op(CalculatorOperation::ArithmeticOperation(
ArithmeticOperation::Ln, ArithmeticOperation::Ln,
)), )),
// Temporary
'V' => self.op(CalculatorOperation::BuildVector),
// Special // Special
'\\' => self.op(CalculatorOperation::Drop), '\\' => self.op(CalculatorOperation::Drop),
' ' => self.op(CalculatorOperation::Dup), ' ' => self.op(CalculatorOperation::Dup),
@ -281,11 +283,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(())
} }
'`' => { '`' => {
@ -344,7 +348,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()?;
@ -371,8 +379,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,
@ -502,6 +516,27 @@ impl Calculator {
Some(r) => Ok(r.clone()), Some(r) => Ok(r.clone()),
} }
} }
/// Pops a usize
pub fn pop_usize(&mut self) -> CalculatorResult<usize> {
let entry = self.peek(0)?;
let f = match entry {
Entry::Number(Number { value }) => value,
Entry::Vector(_) => return Err(CalculatorError::TypeMismatch),
};
// Ensure this can be cast to a usize
if !f.is_finite() || f.is_sign_negative() {
return Err(CalculatorError::ArithmeticError);
}
#[allow(clippy::cast_sign_loss)]
let u = f as usize;
self.direct_state_change(CalculatorStateChange {
pop: OpArgs::Unary(entry),
push: OpArgs::None,
})?;
Ok(u)
}
/// Pops a precision instead of an Entry. Precisions are of type usize /// Pops a precision instead of an Entry. Precisions are of type usize
pub fn pop_precision(&mut self) -> CalculatorResult<usize> { pub fn pop_precision(&mut self) -> CalculatorResult<usize> {
let entry = self.peek(0)?; let entry = self.peek(0)?;
@ -527,6 +562,33 @@ impl Calculator {
Ok(u) Ok(u)
} }
pub fn build_vector(&mut self) -> CalculatorResult<CalculatorStateChange> {
let count = self.pop_usize()?;
let (entries, values): (Vec<Entry>, Vec<Number>) = (0..count)
.map(|i| {
let e = self.peek(i)?;
match e {
// TODO: For now, vectors only contain numbers
Entry::Number(number) => Ok((e, number)),
Entry::Vector(_vector) => {
Err(CalculatorError::TypeMismatch)
}
}
})
.collect::<CalculatorResult<Vec<(Entry, Number)>>>()?
// TODO: Do I have to iter again?
.into_iter()
.unzip();
let entry = Entry::Vector(Vector {
values,
direction: true,
});
Ok(CalculatorStateChange {
pop: OpArgs::Variable(entries),
push: OpArgs::Unary(entry),
})
}
/// Performs a calculator operation such as undo, redo, operator, or dup /// Performs a calculator operation such as undo, redo, operator, or dup
pub fn op(&mut self, op: CalculatorOperation) -> CalculatorResult<()> { pub fn op(&mut self, op: CalculatorOperation) -> CalculatorResult<()> {
// Dup is special -- don't actually run it if l needs to be flushed // Dup is special -- don't actually run it if l needs to be flushed
@ -548,15 +610,15 @@ impl Calculator {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide) => { CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(&a)?))) self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(&a)?)))
} }
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::IntegerDivide) => { CalculatorOperation::ArithmeticOperation(
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(&a)?))) ArithmeticOperation::IntegerDivide,
} ) => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(&a)?))),
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate) => { CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate) => {
self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?))) self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?)))
} }
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::AbsoluteValue) => { CalculatorOperation::ArithmeticOperation(
self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?))) ArithmeticOperation::AbsoluteValue,
} ) => self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?))),
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse) => { CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse) => {
self.unary_op(|a| Ok(OpArgs::Unary(a.inverse()?))) self.unary_op(|a| Ok(OpArgs::Unary(a.inverse()?)))
} }
@ -599,9 +661,14 @@ impl Calculator {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Pow) => { CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Pow) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(&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::BuildVector => self.build_vector(),
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
@ -632,7 +699,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 {
@ -711,6 +782,11 @@ impl Calculator {
} }
} }
OpArgs::Macro(_) | OpArgs::None => {} OpArgs::Macro(_) | OpArgs::None => {}
OpArgs::Variable(entries) => {
if entries.iter().any(|e| !e.is_valid()) {
return Err(CalculatorError::ArithmeticError);
}
}
}; };
match to_pop { match to_pop {
@ -724,6 +800,20 @@ impl Calculator {
self.stack.pop_front(); self.stack.pop_front();
self.stack.pop_front(); self.stack.pop_front();
} }
OpArgs::Variable(entries) => {
if entries
.iter()
.enumerate()
.any(|(i, e)| self.stack_eq(i, e).is_err())
{
// TODO: Return an error if there is one
return Err(CalculatorError::ArithmeticError);
}
for _ in 0..entries.len() {
self.stack.pop_front();
}
}
OpArgs::Macro(_) | OpArgs::None => {} OpArgs::Macro(_) | OpArgs::None => {}
}; };
@ -735,6 +825,11 @@ impl Calculator {
self.stack.push_front(b.clone()); // TODO: Remove the clones self.stack.push_front(b.clone()); // TODO: Remove the clones
self.stack.push_front(a.clone()); // TODO: Remove the clones self.stack.push_front(a.clone()); // TODO: Remove the clones
} }
OpArgs::Variable(entries) => {
for e in entries {
self.stack.push_front(e.clone());
}
}
OpArgs::Macro(_) | OpArgs::None => {} OpArgs::Macro(_) | OpArgs::None => {}
}; };

View File

@ -288,9 +288,15 @@ impl CalculatorEntry for Number {
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String { fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
match display_mode { match display_mode {
CalculatorDisplayMode::Default => format!("{}", self.value), CalculatorDisplayMode::Default => format!("{}", self.value),
CalculatorDisplayMode::Separated { separator } => separated(self.value, *separator), CalculatorDisplayMode::Separated { separator } => {
CalculatorDisplayMode::Scientific { precision } => scientific(self.value, *precision), separated(self.value, *separator)
CalculatorDisplayMode::Engineering { precision } => engineering(self.value, *precision), }
CalculatorDisplayMode::Scientific { precision } => {
scientific(self.value, *precision)
}
CalculatorDisplayMode::Engineering { precision } => {
engineering(self.value, *precision)
}
CalculatorDisplayMode::Fixed { precision } => { CalculatorDisplayMode::Fixed { precision } => {
format!("{:0>.precision$}", self.value, precision = precision) format!("{:0>.precision$}", self.value, precision = precision)
} }
@ -317,7 +323,9 @@ impl CalculatorEntry for Number {
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(),
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).sin(), CalculatorAngleMode::Grads => {
(self.value * std::f64::consts::PI / 200.0).sin()
}
}, },
})) }))
} }
@ -326,7 +334,9 @@ impl CalculatorEntry for Number {
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(),
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).cos(), CalculatorAngleMode::Grads => {
(self.value * std::f64::consts::PI / 200.0).cos()
}
}, },
})) }))
} }
@ -335,7 +345,9 @@ impl CalculatorEntry for Number {
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(),
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).tan(), CalculatorAngleMode::Grads => {
(self.value * std::f64::consts::PI / 200.0).tan()
}
}, },
})) }))
} }
@ -344,7 +356,9 @@ impl CalculatorEntry for Number {
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(),
CalculatorAngleMode::Grads => self.value.asin() * std::f64::consts::PI / 200.0, CalculatorAngleMode::Grads => {
self.value.asin() * std::f64::consts::PI / 200.0
}
}, },
})) }))
} }
@ -353,7 +367,9 @@ impl CalculatorEntry for Number {
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(),
CalculatorAngleMode::Grads => self.value.acos() * std::f64::consts::PI / 200.0, CalculatorAngleMode::Grads => {
self.value.acos() * std::f64::consts::PI / 200.0
}
}, },
})) }))
} }
@ -362,7 +378,9 @@ impl CalculatorEntry for Number {
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(),
CalculatorAngleMode::Grads => self.value.atan() * std::f64::consts::PI / 200.0, CalculatorAngleMode::Grads => {
self.value.atan() * std::f64::consts::PI / 200.0
}
}, },
})) }))
} }
@ -670,7 +688,7 @@ impl Vector {
_ => Err(CalculatorError::ArithmeticError), _ => Err(CalculatorError::ArithmeticError),
}) })
.collect::<CalculatorResult<Vec<Number>>>()?, .collect::<CalculatorResult<Vec<Number>>>()?,
direction: true, direction: self.direction,
})) }))
} }
@ -698,7 +716,7 @@ impl Vector {
_ => Err(CalculatorError::ArithmeticError), _ => Err(CalculatorError::ArithmeticError),
}) })
.collect::<CalculatorResult<Vec<Number>>>()?, .collect::<CalculatorResult<Vec<Number>>>()?,
direction: true, direction: self.direction,
})) }))
} }
fn iterated_binary_num( fn iterated_binary_num(
@ -717,7 +735,7 @@ impl Vector {
_ => Err(CalculatorError::ArithmeticError), _ => Err(CalculatorError::ArithmeticError),
}) })
.collect::<CalculatorResult<Vec<Number>>>()?, .collect::<CalculatorResult<Vec<Number>>>()?,
direction: true, direction: self.direction,
})) }))
} }
} }

View File

@ -27,6 +27,7 @@ pub enum ArithmeticOperation {
#[derive(PartialEq, Debug, Serialize, Deserialize)] #[derive(PartialEq, Debug, Serialize, Deserialize)]
pub enum CalculatorOperation { pub enum CalculatorOperation {
ArithmeticOperation(ArithmeticOperation), ArithmeticOperation(ArithmeticOperation),
BuildVector,
Undo, Undo,
Redo, Redo,
Drop, Drop,
@ -51,6 +52,8 @@ pub enum OpArgs {
Unary(Entry), Unary(Entry),
/// Operation takes 2 arguments, ex: + or - /// Operation takes 2 arguments, ex: + or -
Binary([Entry; 2]), Binary([Entry; 2]),
/// Some variable number of changes
Variable(Vec<Entry>),
/// Operation takes no arguments, ex: push /// Operation takes no arguments, ex: push
None, None,
} }