1enum Operator {
2 Add,
3 Multiply,
4 Divide,
5 Subtract,
6 Exponent,
7}
8enum Token {
9 Number(f64),
10 Operator(Operator),
11}
12struct OperationVector {
13 add: Option<fn(&Vec<Token>, &mut usize, &mut Vec<Token>)>,
14 subtract: Option<fn(&Vec<Token>, &mut usize, &mut Vec<Token>)>,
15 divide: Option<fn(&Vec<Token>, &mut usize, &mut Vec<Token>)>,
16 multiply: Option<fn(&Vec<Token>, &mut usize, &mut Vec<Token>)>,
17 exponent: Option<fn(&Vec<Token>, &mut usize, &mut Vec<Token>)>,
18}
19
20#[derive(Debug)]
21pub struct CalculationError {
22 message: String
23}
24
25fn process_pass(result_array: &Vec<Token>, operations: OperationVector) -> Vec<Token> {
26 let mut index: usize = 0;
27 let mut new_array: Vec<Token> = Vec::new();
28 while index < result_array.len() {
29 match result_array[index] {
30 Token::Number(number) => new_array.push(Token::Number(number)),
31 Token::Operator(Operator::Add) => {
32 match operations.add {
33 Some(func) => func(result_array, &mut index, &mut new_array),
34 None => new_array.push(Token::Operator(Operator::Add)),
35 };
36 }
37 Token::Operator(Operator::Subtract) => {
38 match operations.subtract {
39 Some(func) => func(result_array, &mut index, &mut new_array),
40 None => new_array.push(Token::Operator(Operator::Subtract)),
41 };
42 }
43 Token::Operator(Operator::Multiply) => {
44 match operations.multiply {
45 Some(func) => func(result_array, &mut index, &mut new_array),
46 None => new_array.push(Token::Operator(Operator::Multiply)),
47 };
48 }
49 Token::Operator(Operator::Divide) => {
50 match operations.divide {
51 Some(func) => func(result_array, &mut index, &mut new_array),
52 None => new_array.push(Token::Operator(Operator::Divide)),
53 };
54 }
55 Token::Operator(Operator::Exponent) => {
56 match operations.exponent {
57 Some(func) => func(result_array, &mut index, &mut new_array),
58 None => new_array.push(Token::Operator(Operator::Exponent)),
59 };
60 }
61 }
62 index += 1
63 }
64 return new_array;
65}
66pub fn calculate(to_calculate: &str) -> Result<f64,CalculationError> {
68 let mut result_array: Vec<Token> = Vec::new();
69 let mut number = String::from("");
70 for character in to_calculate.chars() {
71 if let '+' | '-' | '*' | '/' | '^' = character {
72 result_array.push(Token::Number(number.clone().parse::<f64>().unwrap()));
73 number = "".to_string();
74 }
75 match character {
76 '*' => result_array.push(Token::Operator(Operator::Multiply)),
77 '/' => result_array.push(Token::Operator(Operator::Divide)),
78 '-' => result_array.push(Token::Operator(Operator::Subtract)),
79 '+' => result_array.push(Token::Operator(Operator::Add)),
80 '^' => result_array.push(Token::Operator(Operator::Exponent)),
81 _ => {
82 if character.is_ascii_digit() || character == '.' {
83 number.push(character)
84 } else if !character.is_ascii_whitespace() {
85 return Err(CalculationError{
86 message: String::from(format!("Invalid character: {}",character))
87 })
88 }
89 }
90 }
91 }
92 if number != "".to_string() {
93 result_array.push(Token::Number(number.clone().parse::<f64>().unwrap()));
94 }
95 result_array = process_pass(
96 &result_array,
97 OperationVector {
98 add: None,
99 subtract: None,
100 multiply: None,
101 divide: None,
102 exponent: Some(
103 |result_array: &Vec<Token>, index: &mut usize, new_array: &mut Vec<Token>| {
104 if let Token::Number(number) = result_array[*index + (1 as usize)] {
105 if let Token::Number(last_number) = *new_array.last().unwrap() {
106 *new_array.last_mut().unwrap() =
107 Token::Number(f64::powf(last_number, number));
108 *index += 1 as usize;
109 }
110 }
111 },
112 ),
113 },
114 );
115 result_array = process_pass(
116 &result_array,
117 OperationVector {
118 add: None,
119 subtract: None,
120 multiply: Some(
121 |result_array: &Vec<Token>, index: &mut usize, new_array: &mut Vec<Token>| {
122 if let Token::Number(number) = result_array[*index + (1 as usize)] {
123 if let Token::Number(last_number) = *new_array.last().unwrap() {
124 *new_array.last_mut().unwrap() = Token::Number(last_number * number);
125 *index += 1 as usize;
126 }
127 }
128 },
129 ),
130 divide: Some(
131 |result_array: &Vec<Token>, index: &mut usize, new_array: &mut Vec<Token>| {
132 if let Token::Number(number) = result_array[*index + (1 as usize)] {
133 if let Token::Number(last_number) = *new_array.last().unwrap() {
134 *new_array.last_mut().unwrap() = Token::Number(last_number / number);
135 *index += 1 as usize;
136 }
137 }
138 },
139 ),
140 exponent: None,
141 },
142 );
143 result_array = process_pass(
144 &result_array,
145 OperationVector {
146 add: Some(
147 |result_array: &Vec<Token>, index: &mut usize, new_array: &mut Vec<Token>| {
148 if let Token::Number(number) = result_array[*index + (1 as usize)] {
149 if let Token::Number(last_number) = *new_array.last().unwrap() {
150 *new_array.last_mut().unwrap() = Token::Number(last_number + number);
151 *index += 1 as usize;
152 }
153 }
154 },
155 ),
156 subtract: Some(
157 |result_array: &Vec<Token>, index: &mut usize, new_array: &mut Vec<Token>| {
158 if let Token::Number(number) = result_array[*index + (1 as usize)] {
159 if let Token::Number(last_number) = *new_array.last().unwrap() {
160 *new_array.last_mut().unwrap() = Token::Number(last_number - number);
161 *index += 1 as usize;
162 }
163 }
164 },
165 ),
166 divide: None,
167 multiply: None,
168 exponent: None,
169 },
170 );
171 if let Token::Number(value) = result_array[0] {
172 return Ok(value);
173 }
174 return Ok(0.0);
175}
176#[cfg(test)] mod tests { use crate::calculate;
179 #[test]
180 fn test_basic() {
181 match calculate("2+2"){
182 Ok(value)=>{assert_eq!(value,4.0)},
183 Err(value)=>{assert!(false,value)}
184 }
185 }
186 #[test]
187 fn test_all() {
188 match calculate("2+7*4^2-5"){
189 Ok(value)=>{assert_eq!(value,109.0)},
190 Err(value)=>{assert!(false,value)}
191 }
192 }
193 #[test]
194 fn test_decimal() {
195 match calculate("2.1*2+5.35"){
196 Ok(value)=>{assert_eq!(value,9.55)},
197 Err(value)=>{assert!(false,value)}
198 }
199 }
200 #[test]
201 fn test_invalid() {
202 match calculate("invalid"){
203 Ok(value)=>{assert!(false,"Invalid character returned number: {}",value)},
204 Err(value)=>{assert!(true,value)}
205 }
206 }
207}