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

View File

@ -16,8 +16,8 @@
#![warn(clippy::pedantic)]
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
pub mod result;
pub use result::{Error, Result, CalculateResult};
pub mod base;
pub use base::{Error, Result, Value};
pub mod term;
pub use term::*;
@ -45,7 +45,7 @@ pub struct Calculator;
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
impl Calculator {
/// 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");
let t = Term::new(t)?;
trace!("term has been parsed, starting Calculation");
@ -60,7 +60,7 @@ impl Calculator {
/// 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> {
pub fn calc(mut t: Term) -> Result<Value> {
trace!("Calculating term {t:?}");
t.prepare();
t.process();
@ -68,7 +68,7 @@ impl Calculator {
error!("Term was processed but no result was assigned.");
return Err(Error::SyntaxError)
}
return Ok(t.result.unwrap())
return t.result.unwrap()
}
}

View File

@ -20,7 +20,8 @@
use std::collections::VecDeque;
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
pub use super::{Error, Result, CalculateResult};
pub use super::{Error, Result, Value, base::{self, *}};
use crate::logger::*;
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
@ -31,49 +32,6 @@ pub use super::{Error, Result, CalculateResult};
//// 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
@ -86,7 +44,7 @@ enum Token {
Operator(Operator),
/// A concrete value that we can calculate something with. May be a constant, integer, float,
/// etc.
Value(),
Value(super::base::Value),
/// A variable of some kind that will be present in the result
Variable(char),
}
@ -101,7 +59,7 @@ 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>,
pub result: Option<Result<Value>>,
/////////////////////////////////////
///// internal values following /////
/////////////////////////////////////
@ -126,16 +84,60 @@ impl Term {
}
/// Prepare the term for the processing.
pub fn prepare(&mut self) {
pub fn prepare(&mut self) -> Result<()> {
// 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
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 //////////////////////////////////////////////////////////////////////////////