tokens and terms

This commit is contained in:
Christoph J. Scherr 2023-09-12 21:48:55 +02:00
parent 34578c0b11
commit 8fc8432bdb
3 changed files with 126 additions and 80 deletions

View File

@ -13,7 +13,7 @@
//// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// //// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
use std::fmt::Display; use std::fmt::Display;
use num_traits; pub use num_traits::PrimInt;
//// TYPES ///////////////////////////////////////////////////////////////////////////////////////// //// TYPES /////////////////////////////////////////////////////////////////////////////////////////
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
@ -25,6 +25,50 @@ pub type Result<T> = std::result::Result<T, Error>;
//// MACROS //////////////////////////////////////////////////////////////////////////////////////// //// MACROS ////////////////////////////////////////////////////////////////////////////////////////
//// ENUMS ///////////////////////////////////////////////////////////////////////////////////////// //// 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,
}
////////////////////////////////////////////////////////////////////////////////////////////////////
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -33,15 +77,15 @@ pub enum Error {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Debug)] #[derive(Debug)]
pub enum CalculateResult { pub enum Value {
Variable(VarResult), Variable(VarVal),
Numerical(NumericResult), Numerical(NumVal),
Complex(ComplexResult), Complex(ComplVal),
} }
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug)] #[derive(Debug)]
pub enum NumericResult { pub enum NumVal {
Signed(i128), Signed(i128),
Unsigned(u128), Unsigned(u128),
Float(f64) Float(f64)
@ -49,61 +93,61 @@ pub enum NumericResult {
//// STRUCTS /////////////////////////////////////////////////////////////////////////////////////// //// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
#[derive(Debug)] #[derive(Debug)]
pub struct VarResult { pub struct VarVal {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
#[derive(Debug)] #[derive(Debug)]
pub struct ComplexResult { pub struct ComplVal {
} }
//// IMPLEMENTATION //////////////////////////////////////////////////////////////////////////////// //// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
impl<T: num_traits::PrimInt> From<T> for NumericResult where impl<T: num_traits::PrimInt> From<T> for NumVal where
u128: TryFrom<T>, u128: TryFrom<T>,
u128: TryFrom<T> { u128: TryFrom<T> {
fn from(value: T) -> Self { fn from(value: T) -> Self {
if T::min_value().is_zero() { if T::min_value().is_zero() {
// unsigned data types // unsigned data types
// `u128` is the largest unsigned datatype, any other type will fit. // `u128` is the largest unsigned datatype, any other type will fit.
NumericResult::Unsigned(value.to_u128().unwrap()) NumVal::Unsigned(value.to_u128().unwrap())
} }
else { else {
// signed data types // signed data types
// `i128` is the largest unsigned datatype, any other type will fit. // `i128` is the largest unsigned datatype, any other type will fit.
NumericResult::Signed(value.to_i128().unwrap()) NumVal::Signed(value.to_i128().unwrap())
} }
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
impl<T: num_traits::PrimInt> From<T> for CalculateResult where impl<T: PrimInt> From<T> for Value where
u128: TryFrom<T>, u128: TryFrom<T>,
u128: TryFrom<T> { u128: TryFrom<T> {
fn from(value: T) -> Self { fn from(value: T) -> Self {
NumericResult::from(value).into() NumVal::from(value).into()
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
impl From<NumericResult> for CalculateResult { impl From<NumVal> for Value {
fn from(value: NumericResult) -> Self { fn from(value: NumVal) -> Self {
CalculateResult::Numerical(value) Value::Numerical(value)
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
impl Display for CalculateResult { impl Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
CalculateResult::Numerical(val) => { Value::Numerical(val) => {
write!(f, "{}", val) write!(f, "{}", val)
} }
CalculateResult::Complex(val) => { Value::Complex(val) => {
write!(f, "{}", val) write!(f, "{}", val)
} }
CalculateResult::Variable(val) => { Value::Variable(val) => {
write!(f, "{}", val) write!(f, "{}", val)
} }
} }
@ -111,16 +155,16 @@ impl Display for CalculateResult {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
impl Display for NumericResult { impl Display for NumVal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
NumericResult::Float(val) => { NumVal::Float(val) => {
write!(f, "{val}") write!(f, "{val}")
} }
NumericResult::Signed(val) => { NumVal::Signed(val) => {
write!(f, "{val}") write!(f, "{val}")
} }
NumericResult::Unsigned(val) => { NumVal::Unsigned(val) => {
write!(f, "{val}") write!(f, "{val}")
} }
} }
@ -128,14 +172,14 @@ impl Display for NumericResult {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
impl Display for ComplexResult { impl Display for ComplVal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "") write!(f, "")
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
impl Display for VarResult { impl Display for VarVal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "") write!(f, "")
} }

View File

@ -16,8 +16,8 @@
#![warn(clippy::pedantic)] #![warn(clippy::pedantic)]
//// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// //// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
pub mod result; pub mod base;
pub use result::{Error, Result, CalculateResult}; pub use base::{Error, Result, Value};
pub mod term; pub mod term;
pub use term::*; pub use term::*;
@ -45,7 +45,7 @@ pub struct Calculator;
//// IMPLEMENTATION //////////////////////////////////////////////////////////////////////////////// //// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
impl Calculator { impl Calculator {
/// Do a single calculation without doing anything else /// Do a single calculation without doing anything else
pub fn oneshot(t: String) -> Result<CalculateResult> { pub fn oneshot(t: String) -> Result<Value> {
trace!(orig=t, "parsing original string to Term"); trace!(orig=t, "parsing original string to Term");
let t = Term::new(t)?; let t = Term::new(t)?;
trace!("term has been parsed, starting Calculation"); trace!("term has been parsed, starting Calculation");
@ -60,7 +60,7 @@ impl Calculator {
/// Calculate the final value of any term. /// Calculate the final value of any term.
/// ///
/// This method only processes a single term at a time, without caching. /// This method only processes a single term at a time, without caching.
pub fn calc(mut t: Term) -> Result<CalculateResult> { pub fn calc(mut t: Term) -> Result<Value> {
trace!("Calculating term {t:?}"); trace!("Calculating term {t:?}");
t.prepare(); t.prepare();
t.process(); t.process();
@ -68,7 +68,7 @@ impl Calculator {
error!("Term was processed but no result was assigned."); error!("Term was processed but no result was assigned.");
return Err(Error::SyntaxError) return Err(Error::SyntaxError)
} }
return Ok(t.result.unwrap()) return t.result.unwrap()
} }
} }

View File

@ -20,7 +20,8 @@
use std::collections::VecDeque; use std::collections::VecDeque;
//// IMPORTS /////////////////////////////////////////////////////////////////////////////////////// //// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
pub use super::{Error, Result, CalculateResult}; pub use super::{Error, Result, Value, base::{self, *}};
use crate::logger::*;
//// TYPES ///////////////////////////////////////////////////////////////////////////////////////// //// TYPES /////////////////////////////////////////////////////////////////////////////////////////
@ -31,49 +32,6 @@ pub use super::{Error, Result, CalculateResult};
//// MACROS //////////////////////////////////////////////////////////////////////////////////////// //// MACROS ////////////////////////////////////////////////////////////////////////////////////////
//// ENUMS ///////////////////////////////////////////////////////////////////////////////////////// //// 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 /// ## Parsed value to be calculated
@ -86,7 +44,7 @@ enum Token {
Operator(Operator), Operator(Operator),
/// A concrete value that we can calculate something with. May be a constant, integer, float, /// A concrete value that we can calculate something with. May be a constant, integer, float,
/// etc. /// etc.
Value(), Value(super::base::Value),
/// A variable of some kind that will be present in the result /// A variable of some kind that will be present in the result
Variable(char), Variable(char),
} }
@ -101,7 +59,7 @@ pub struct Term {
/// the original expression to calculate /// the original expression to calculate
pub original: String, pub original: String,
/// the calculated result, may be of diffrent types, see [`crate::math::calculator::result`]. /// the calculated result, may be of diffrent types, see [`crate::math::calculator::result`].
pub result: Option<CalculateResult>, pub result: Option<Result<Value>>,
///////////////////////////////////// /////////////////////////////////////
///// internal values following ///// ///// internal values following /////
///////////////////////////////////// /////////////////////////////////////
@ -126,16 +84,60 @@ impl Term {
} }
/// Prepare the term for the processing. /// Prepare the term for the processing.
pub fn prepare(&mut self) { pub fn prepare(&mut self) -> Result<()> {
// TODO: shunting yard // TODO: shunting yard
// Storage for unfinished tokens
let mut unfinished_chars: Vec<char> = Vec::new();
for c in self.original.chars() {
// FIXME: this completely ignores shunting yard,
// only being on the lookout for values
if Self::is_tok(&unfinished_chars) {
let tok = Self::to_tok(unfinished_chars)?;
// TODO: handle the token, depending on type, precedence and so on
self.output_queue.push_front(tok);
unfinished_chars = Vec::new();
}
else {
unfinished_chars.push(c);
}
}
Ok(())
} }
pub fn process(&mut self) { /// Process a prepared term, calculating it's result
pub fn process(&mut self) -> Result<()> {
debug!("processing term: {:#?}", self);
debug!("queue: {:#?}", self.output_queue);
// TODO: process RPN and set result // TODO: process RPN and set result
self.result = Some(CalculateResult::Numerical(19.into())) self.result = Some(Ok(19.into()));
Ok(())
}
/// Convert a character into a token
///
/// Returns: A tuple with a [`Token`] and a [`bool`]. If the bool is false, the [`Token`] is
/// marked as "incomplete", meaning that the character cannot be used yet.
fn to_tok(s: Vec<char>) -> Result<Token> {
Ok(19.into())
}
fn is_tok(s: &Vec<char>) -> bool {
false
} }
} }
////////////////////////////////////////////////////////////////////////////////////////////////////
impl<T> From<T> for Token where
T: Into<Value>,
T: PrimInt,
u128: TryFrom<T>
{
fn from(value: T) -> Self {
Token::Value(base::Value::from(value))
}
}
//// PUBLIC FUNCTIONS ////////////////////////////////////////////////////////////////////////////// //// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////