terms module design

This commit is contained in:
Christoph J. Scherr 2023-09-12 21:08:18 +02:00
parent 1e176814e9
commit 34578c0b11
2 changed files with 120 additions and 71 deletions

View File

@ -18,6 +18,8 @@
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
pub mod result;
pub use result::{Error, Result, CalculateResult};
pub mod term;
pub use term::*;
#[allow(unused_imports)] // we possibly want to use all log levels
use crate::logger::{trace, debug, info, warn, error};
@ -31,74 +33,21 @@ use crate::logger::{trace, debug, info, warn, error};
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
// #[non_exhaustive]
// #[derive(Debug)]
// pub enum Constants {
// Pi
// }
////////////////////////////////////////////////////////////////////////////////////////////////////
#[non_exhaustive]
#[derive(Debug)]
/// ## Supported Operations
///
/// This `enum` contains all operations supported in this module.
pub enum Operations {
/// Mathmatical addition
Addition,
/// Mathmatical subtraction
Subtraction,
/// Mathmatical multiplication
Multiplication,
/// Mathmatical division
Division,
/// Mathmatical modulo, finite field arithmetic
Modulo,
/// Any function, seel [`Function`]
Function(Function)
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// ## Supported Functions
///
/// This `enum` contains all functions supported in this module.
///
/// A function has a name followed by braces directly afterwards.
/// A function may have 0 to 31 Arguments.
///
/// Example: `sqrt(19)`, `floor(19.9)`
#[non_exhaustive]
#[derive(Debug)]
pub enum Function {
/// Draw the mathmatical root, attribute n is the nth root
Root(u16),
/// round up
Floor,
/// round down
Ceil,
/// round to nearest integer
/// (commercial rounding)
Round,
}
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
/// ## A Calculator object
/// ## A Calculator struct
///
/// This struct does not do anything at the moment, but aims to be the target for high level
/// control. Instead of using the [`Calculator`], you could just use the [`Term`] struct for
/// lower level control.
pub struct Calculator;
////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Debug)]
pub struct Term {
original: String,
result: Option<CalculateResult>,
parts: Vec<String>
}
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
impl Calculator {
/// Do a single calculation without doing anything else
pub fn oneshot(t: String) -> Result<CalculateResult> {
trace!(orig=t, "parsing original string to Term");
let mut t = Term::new(t);
let t = Term::new(t)?;
trace!("term has been parsed, starting Calculation");
debug!("parsed term: {t:#?}");
Self::calc(t)
@ -106,24 +55,20 @@ impl Calculator {
/// ## Calculate a [`Term`]
///
/// This method makes use of the
/// This method makes use of the
/// [shunting yard algorithm](https://en.wikipedia.org/wiki/Shunting_yard_algorithm) to
/// Calculate the final value of any term.
///
/// This method only processes a single term at a time, without caching.
pub fn calc(mut t: Term) -> Result<CalculateResult> {
trace!("Calculating term {t:?}");
return Ok(CalculateResult::from(0))
}
}
impl Term {
pub fn new(orig: String) -> Self {
Term {
original: orig,
result: None,
parts: Vec::new()
t.prepare();
t.process();
if t.result.is_none() {
error!("Term was processed but no result was assigned.");
return Err(Error::SyntaxError)
}
return Ok(t.result.unwrap())
}
}

View File

@ -17,7 +17,10 @@
// enable clippy's extra lints, the pedantic version
#![warn(clippy::pedantic)]
use std::collections::VecDeque;
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
pub use super::{Error, Result, CalculateResult};
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
@ -28,10 +31,111 @@
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
/// ## Supported Operations
///
/// This `enum` contains all operations supported in this module.
#[non_exhaustive]
#[derive(Debug)]
pub enum Operator {
/// Mathmatical addition
Addition,
/// Mathmatical subtraction
Subtraction,
/// Mathmatical multiplication
Multiplication,
/// Mathmatical division
Division,
/// Mathmatical modulo, finite field arithmetic
Modulo,
/// Any function, seel [`Function`]
Function(Function)
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// ## Supported Functions
///
/// This `enum` contains all functions supported in this module.
///
/// A function has a name followed by braces directly afterwards.
/// A function may have 0 to 31 Arguments.
///
/// Example: `sqrt(19)`, `floor(19.9)`
#[non_exhaustive]
#[derive(Debug)]
pub enum Function {
/// Draw the mathmatical root, attribute n is the nth root
Root(u16),
/// round up
Floor,
/// round down
Ceil,
/// round to nearest integer
/// (commercial rounding)
Round,
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// ## Parsed value to be calculated
///
/// This enum represents anything that goes to the output queue of [`Term::prepare()`] and will
/// then be used to actually calculate something in [`Term::process()`].
#[derive(Debug)]
enum Token {
/// Some kind of operator
Operator(Operator),
/// A concrete value that we can calculate something with. May be a constant, integer, float,
/// etc.
Value(),
/// A variable of some kind that will be present in the result
Variable(char),
}
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
/// ## Term that can be calculated
///
/// Represents a signular term, that can be calculated. Terms will be evaluated by the [`Term::prepare`]
/// function, afterwards calculated (as much as possible) in the [`Term::process`] function.
///
#[derive(Debug)]
pub struct Term {
/// the original expression to calculate
pub original: String,
/// the calculated result, may be of diffrent types, see [`crate::math::calculator::result`].
pub result: Option<CalculateResult>,
/////////////////////////////////////
///// internal values following /////
/////////////////////////////////////
operator_stack: Vec<Operator>,
output_queue: VecDeque<Token>
}
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
impl Term {
/// Build a new term from an expression
///
/// Invalid terms will result in an [`Err`].
pub fn new(orig: String) -> Result<Term> {
return Ok(
Term {
original: orig,
result: None,
operator_stack: Vec::new(),
output_queue: VecDeque::new()
}
)
}
/// Prepare the term for the processing.
pub fn prepare(&mut self) {
// TODO: shunting yard
}
pub fn process(&mut self) {
// TODO: process RPN and set result
self.result = Some(CalculateResult::Numerical(19.into()))
}
}
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////