calculator_lib/
lib.rs

1use std::fmt::Display;
2
3use anyhow::bail;
4use thiserror::Error;
5#[derive(Debug, Clone, PartialEq)]
6pub enum Expression {
7    Number(f64),
8    Addition,
9    Subtraction,
10    Division,
11    Multiplication,
12    Power,
13
14    /// Variable refers to ```X```, variables as in mathematical sense
15    Variable,
16
17    Bracket(Vec<Expression>),
18
19    BracketOpen,
20    BracketClose,
21}
22
23impl Expression {
24    pub fn get_number(&self) -> anyhow::Result<f64> {
25        if let Expression::Number(num) = self {
26            return Ok(*num);
27        } else {
28            bail!("Expression is not a number.");
29        }
30    }
31}
32
33impl ToString for Expression {
34    fn to_string(&self) -> String {
35        match self {
36            Expression::Number(num) => num.to_string(),
37            Expression::Addition => String::from("+"),
38            Expression::Subtraction => String::from("-"),
39            Expression::Division => String::from("/"),
40            Expression::Multiplication => String::from("*"),
41            Expression::Power => String::from("^"),
42            Expression::Variable => String::from("x"),
43            Expression::Bracket(inner) => inner
44                .iter()
45                .map(|expr| format!("{} ", expr.to_string()))
46                .collect::<Vec<String>>()
47                .concat(),
48            Expression::BracketOpen => String::from("("),
49            Expression::BracketClose => String::from(")"),
50        }
51    }
52}
53
54#[derive(Default, Debug)]
55pub struct Calculator {
56    inner: Vec<Expression>,
57}
58
59impl Calculator {
60    /// This function creates a new ```Calculator``` instance, and automaticly parses the passed in string.
61    pub fn new(input: impl ToString) -> anyhow::Result<Self> {
62        let calculator_instance = Self {
63            inner: Self::parse(input.to_string())?,
64        };
65
66        Ok(calculator_instance)
67    }
68
69    /// Returns the parsed expressions from the ```Calculator``` instance
70    pub fn into_inner(&self) -> Vec<Expression> {
71        self.inner.clone()
72    }
73
74    /// Parses input string and outputs a vector of expressions
75    fn parse(input: String) -> anyhow::Result<Vec<Expression>> {
76        let unparsed_tokens = Self::tokenize(input)?;
77        let parsed_tokens = Self::evaluate(unparsed_tokens)?;
78
79        Ok(parsed_tokens)
80    }
81
82    /// Tokenizes the string
83    fn tokenize(input: String) -> anyhow::Result<Vec<Expression>> {
84        let mut tokens: Vec<Expression> = vec![];
85
86        let mut num_buffer: String = String::new();
87
88        let mut last_expr: Option<Expression> = None;
89
90        for (idx, char) in input.chars().enumerate() {
91            let expression = match char.to_ascii_lowercase() {
92                '+' => Expression::Addition,
93                '-' =>  {
94                    Expression::Subtraction
95
96                },
97                '*' => Expression::Multiplication,
98                '/' | ':' => Expression::Division,
99                '^' => Expression::Power,
100                ' ' => {
101                    if !num_buffer.is_empty() {
102                        tokens.push(Expression::Number(num_buffer.parse()?));
103
104                        num_buffer.clear();
105                    }
106
107                    continue;
108                }
109                'x' => Expression::Variable,
110                '(' => Expression::BracketOpen,
111                ')' => Expression::BracketClose,
112                _ => {
113                    if let Some(digit) = char.to_digit(10) {
114                        num_buffer.push_str(&digit.to_string());
115
116                        continue;
117                    } else if char == '.' {
118                        num_buffer.push('.');
119
120                        continue;
121                    } 
122                    else {
123                        bail!(CalculatorError::new(
124                            String::from(
125                                "If you meant to define an unknown, only 'X' is available"
126                            ),
127                            input,
128                            idx
129                        ));
130                    }
131                }
132            };
133
134            last_expr = Some(expression.clone());
135
136            if !num_buffer.is_empty() {
137                tokens.push(Expression::Number(num_buffer.parse::<f64>()?));
138
139                num_buffer.clear();
140            }
141
142            tokens.push(expression);
143        }
144
145        if !num_buffer.is_empty() {
146            tokens.push(Expression::Number(num_buffer.parse::<f64>()?));
147        }
148
149        Ok(tokens)
150    }
151
152    /// Evaluates (Parses) the tokens
153    /// This function adds the ```Expression::Bracket``` enum.
154    fn evaluate(mut input: Vec<Expression>) -> anyhow::Result<Vec<Expression>> {
155        let mut eval_buf: Vec<Expression> = vec![];
156        let mut equation_buf: Vec<Expression> = vec![];
157
158        let mut bracket_counter = 0;
159        let mut bracket_pos: (usize, usize) = (0, 0);
160
161        let mut iter_idx = 0;
162
163        while input.len() > iter_idx {
164            let expr = input[iter_idx].clone();
165
166            match &expr {
167                Expression::BracketOpen => {
168                    if bracket_counter == 0 {
169                        bracket_pos.0 = iter_idx;
170                    } else {
171                        equation_buf.push(Expression::BracketOpen);
172                    }
173
174                    bracket_counter += 1;
175                }
176                Expression::BracketClose => {
177                    bracket_counter -= 1;
178
179                    if bracket_counter == 0 {
180                        bracket_pos.1 = iter_idx;
181
182                        input.drain(bracket_pos.0..bracket_pos.1);
183
184                        eval_buf.insert(
185                            bracket_pos.0,
186                            Expression::Bracket(Self::evaluate(equation_buf.clone())?),
187                        );
188
189                        iter_idx = bracket_pos.0;
190
191                        equation_buf.clear();
192                    } else {
193                        equation_buf.push(Expression::BracketClose);
194                    }
195                }
196                _ => {
197                    if bracket_counter > 0 {
198                        equation_buf.push(expr.clone());
199                    } else {
200                        eval_buf.push(expr.clone());
201                    }
202                }
203            }
204
205            iter_idx += 1;
206        }
207
208        Ok(eval_buf)
209    }
210
211    /// Calculates the result based on the parsed string. The reason this function is separate, is that you can use different variable values for calculations, without reparsing the data.
212    pub fn calculate(&self, variable_value: Option<f64>) -> anyhow::Result<f64> {
213        return Self::__calc(self.inner.clone(), variable_value);
214    }
215
216    /// Private function for calculating
217    fn __calc(mut input: Vec<Expression>, variable_value: Option<f64>) -> anyhow::Result<f64> {
218        let mut iter_idx = 0;
219        let mut last_expr: Option<Expression> = None;
220
221        while input.len() > iter_idx {
222            let expr = input[iter_idx].clone();
223
224            match expr {
225                Expression::Bracket(ref inner) => {
226                    input.remove(iter_idx);
227                    input.insert(
228                        iter_idx,
229                        Expression::Number(Self::__calc(inner.to_vec(), variable_value)?),
230                    );
231
232                    if matches!(last_expr, Some(Expression::Bracket(_)))
233                        || matches!(last_expr, Some(Expression::Number(_)))
234                    {
235                        input.insert(iter_idx, Expression::Multiplication);
236                        last_expr = None;
237                    }
238
239                    continue;
240                }
241                Expression::Variable => {
242                    let variable_value = &variable_value.ok_or_else(|| {
243                        CalculatorError::from_expression_list(
244                            String::from("A variable was used in the equation, but a default value has not been set."),
245                            input.clone(),
246                            iter_idx
247                        )
248                    })?;
249
250                    input[iter_idx] = Expression::Number(*variable_value);
251
252                    continue;
253                }
254                Expression::BracketOpen => unreachable!(),
255                Expression::BracketClose => unreachable!(),
256                Expression::Number(_) => (),
257                _ => {
258                    let lhs = match input.clone().get(iter_idx - 1).ok_or(
259                        CalculatorError::from_expression_list(
260                            String::from("Expression not found."),
261                            input.clone(),
262                            iter_idx,
263                        ),
264                    )? {
265                        Expression::Bracket(inner) => Self::__calc(inner.to_vec(), variable_value)?,
266                        Expression::Number(inner) => inner.clone(),
267                        _ => {
268                            bail!(CalculatorError::from_expression_list(
269                                String::from("Expression can not be turned into a number."),
270                                input.clone(),
271                                iter_idx
272                            ))
273                        }
274                    };
275
276                    let input_clone = input.clone();
277                    let rhs = match input_clone.get(iter_idx + 1).ok_or(
278                        CalculatorError::from_expression_list(
279                            String::from("Expression not found."),
280                            input.clone(),
281                            iter_idx,
282                        ),
283                    )? {
284                        Expression::Bracket(inner) => Self::__calc(inner.to_vec(), variable_value)?,
285                        Expression::Number(inner) => *inner,
286                        _ => {
287                            bail!(CalculatorError::from_expression_list(
288                                String::from("Expression can not be turned into a number."),
289                                input.clone(),
290                                iter_idx
291                            ))
292                        }
293                    };
294
295                    if expr == Expression::Multiplication {
296                        input.drain(iter_idx - 1..=iter_idx + 1);
297                        input.insert(iter_idx - 1, Expression::Number(lhs * rhs));
298                        iter_idx -= 1;
299                    } else if expr == Expression::Division {
300                        input.drain(iter_idx - 1..=iter_idx + 1);
301                        input.insert(iter_idx - 1, Expression::Number(lhs / rhs));
302                        iter_idx -= 1;
303                    } else if expr == Expression::Power {
304                        input.drain(iter_idx - 1..=iter_idx + 1);
305                        input.insert(iter_idx - 1, Expression::Number(lhs.powf(rhs)));
306                        iter_idx -= 1;
307                    }
308                }
309            }
310
311            last_expr = Some(expr);
312            iter_idx += 1;
313        }
314
315        iter_idx = 0;
316
317        while input.len() > iter_idx {
318            let expr = input[iter_idx].clone();
319
320            match expr {
321                Expression::Bracket(ref inner) => {
322                    input.remove(iter_idx);
323                    input.insert(
324                        iter_idx,
325                        Expression::Number(Self::__calc(inner.to_vec(), variable_value)?),
326                    );
327
328                    if matches!(last_expr, Some(Expression::Bracket(_)))
329                        || matches!(last_expr, Some(Expression::Number(_)))
330                    {
331                        input.insert(iter_idx, Expression::Multiplication);
332                        last_expr = None;
333                    }
334
335                    continue;
336                }
337                Expression::Variable => {
338                    let variable_value = &variable_value.ok_or_else(|| {
339                        CalculatorError::from_expression_list(
340                            String::from("A variable was used in the equation, but a default value has not been set."),
341                            input.clone(),
342                            iter_idx
343                        )
344                    })?;
345
346                    input[iter_idx] = Expression::Number(*variable_value);
347
348                    continue;
349                }
350                Expression::BracketOpen => unreachable!(),
351                Expression::BracketClose => unreachable!(),
352                Expression::Number(_) => (),
353                _ => {
354                    let lhs = match input.clone().get(iter_idx - 1).ok_or(
355                        CalculatorError::from_expression_list(
356                            String::from("Expression not found."),
357                            input.clone(),
358                            iter_idx,
359                        ),
360                    )? {
361                        Expression::Bracket(inner) => Self::__calc(inner.to_vec(), variable_value)?,
362                        Expression::Number(inner) => *inner,
363                        _ => {
364                            bail!(CalculatorError::from_expression_list(
365                                String::from("Expression can not be turned into a number."),
366                                input.clone(),
367                                iter_idx
368                            ))
369                        }
370                    };
371
372                    let input_clone = input.clone();
373                    let rhs = match input_clone.get(iter_idx + 1).ok_or(
374                        CalculatorError::from_expression_list(
375                            String::from("Expression not found."),
376                            input.clone(),
377                            iter_idx,
378                        ),
379                    )? {
380                        Expression::Bracket(inner) => Self::__calc(inner.to_vec(), variable_value)?,
381                        Expression::Number(inner) => *inner,
382                        _ => {
383                            bail!(CalculatorError::from_expression_list(
384                                String::from("Expression can not be turned into a number."),
385                                input.clone(),
386                                iter_idx
387                            ))
388                        }
389                    };
390
391                    if expr == Expression::Addition {
392                        input.drain(iter_idx - 1..=iter_idx + 1);
393                        input.insert(iter_idx - 1, Expression::Number(lhs + rhs));
394                        iter_idx -= 1;
395                    } else if expr == Expression::Subtraction {
396                        input.drain(iter_idx - 1..=iter_idx + 1);
397                        input.insert(iter_idx - 1, Expression::Number(lhs - rhs));
398                        iter_idx -= 1;
399                    } else if expr == Expression::Variable {
400                        input.drain(iter_idx - 1..=iter_idx + 1);
401                        input.insert(iter_idx - 1, Expression::Number(0.0));
402                        iter_idx -= 1;
403                    }
404                }
405            }
406
407            last_expr = Some(expr);
408            iter_idx += 1;
409        }
410
411        if input.is_empty() || input.len() != 1 {
412            bail!(CalculatorError::from_expression_list(
413                String::from("Empty equation or invalid equation."),
414                input.clone(),
415                1
416            ));
417        }
418
419        Ok(input[0].get_number()?)
420    }
421}
422
423#[derive(Error, Debug)]
424pub struct CalculatorError {
425    message: String,
426
427    equation: String,
428
429    error_idx: usize,
430}
431
432impl Display for CalculatorError {
433    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
434        f.write_str(&format!(
435            "Syntax error!\nMessage: {}\n{}\n{}",
436            self.message,
437            self.equation,
438            {
439                let mut indentation = String::new();
440
441                for _ in 0..self.error_idx {
442                    indentation.push(' ');
443                }
444
445                indentation.push('^');
446
447                indentation
448            }
449        ))
450    }
451}
452
453impl CalculatorError {
454    pub fn new(message: String, equation: String, error_idx: usize) -> Self {
455        Self {
456            message,
457            equation,
458            error_idx,
459        }
460    }
461
462    pub fn from_expression_list(
463        message: String,
464        equation: Vec<Expression>,
465        error_idx: usize,
466    ) -> Self {
467        let mut equation_string = String::new();
468
469        for expr in equation {
470            equation_string.push_str(&format!("{} ", expr.to_string()));
471        }
472
473        Self {
474            message,
475            equation: equation_string,
476            error_idx: {
477                if error_idx != 0 {
478                    error_idx * 2 - 1
479                } else {
480                    0
481                }
482            },
483        }
484    }
485}