Skip to content

Commit ead312a

Browse files
committed
Introducing num for arbitrary natural number calculation with BigInt
1 parent 633362c commit ead312a

File tree

7 files changed

+105
-82
lines changed

7 files changed

+105
-82
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ Cargo.lock
33
/.vscode
44
.yarer_history
55
/vendor
6+
.idea

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ env_logger = "0.11.2"
2727
anyhow = "1.0.72"
2828
thiserror = "1.0.44"
2929
lazy_static = "1.4"
30+
num = "0.4.1"
31+
num-bigint = "0.4.4"
32+
num-traits = "0.2.18"
33+
bigdecimal = "0.4.2"
3034

3135
[profile.release]
3236
opt-level = 3

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
//!
5555
//! let result: Number = resolver.resolve().unwrap();
5656
//!
57-
//! let int : i32 = i32::from(result);
57+
//! let int : i32 = i32::from(&result);
5858
//! // or
5959
//! let float : f64 = f64::from(result);
6060
//! ```

src/parser.rs

+18-16
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ use once_cell::sync::Lazy;
55
use regex::Regex;
66

77
/// The Parser has 2 primary functions:
8-
/// to parse the math expression with a Regex and to tokenise the math &str expression
8+
/// to parse the math expression with a Regex and to tokenise the math &[str] expression
99
///
1010
#[derive(Debug)]
1111
pub struct Parser;
1212

1313
static EXPRESSION_REGEX: Lazy<Regex> =
14-
Lazy::new(|| Regex::new(r"(\d+\.?\d*|\.\d+|[-+*/^()=×÷!]|[a-zA-Z_][a-zA-Z0-9_]*|)").unwrap());
14+
Lazy::new(|| Regex::new(r"(\d+\.?\d*|\.\d+|[-+*/^()=×÷!]|[a-zA-Z_][a-zA-Z0-9_]*|)")
15+
.expect("Should compile regex"));
1516

1617
impl Parser {
1718
/// Parses and splits a &str into a vec of &str with
@@ -33,10 +34,10 @@ impl Parser {
3334
let mut mod_vec: Vec<Token> = Vec::new();
3435
let mut expect_operand_next = true;
3536

36-
for &token in v {
37+
for token in v {
3738
debug!("{}", token);
3839

39-
match token {
40+
match &token {
4041
Token::Operand(_) | Token::Variable(_) | Token::Operator(Operator::Fac) => {
4142
expect_operand_next = false;
4243
}
@@ -45,11 +46,11 @@ impl Parser {
4546
debug!("-> Unary operator detected");
4647
match o {
4748
token::Operator::Add => {
48-
// an unary + is simply ignored.
49+
// an unary + can be simply ignored.
4950
continue;
5051
}
5152
token::Operator::Sub => {
52-
// an unary - is a special right-associative op with high precedence
53+
// an unary - is a special right-associative op with the highest precedence
5354
mod_vec.push(token::Token::Operator(token::Operator::Une));
5455
continue;
5556
}
@@ -60,14 +61,15 @@ impl Parser {
6061
}
6162
_ => (),
6263
}
63-
mod_vec.push(token);
64+
mod_vec.push(token.clone());
6465
}
6566
mod_vec
6667
}
6768
}
6869

6970
#[cfg(test)]
7071
mod tests {
72+
use num_bigint::BigInt;
7173
use super::*;
7274
use crate::token::{Bracket, Number, Operator};
7375

@@ -76,16 +78,16 @@ mod tests {
7678
assert_eq!(
7779
Parser::parse("1+2*3/(4-5)"),
7880
(vec![
79-
Token::Operand(Number::NaturalNumber(1)),
81+
Token::Operand(Number::NaturalNumber(BigInt::from(1u8))),
8082
Token::Operator(Operator::Add),
81-
Token::Operand(Number::NaturalNumber(2)),
83+
Token::Operand(Number::NaturalNumber(BigInt::from(2u8))),
8284
Token::Operator(Operator::Mul),
83-
Token::Operand(Number::NaturalNumber(3)),
85+
Token::Operand(Number::NaturalNumber(BigInt::from(3u8))),
8486
Token::Operator(Operator::Div),
8587
Token::Bracket(Bracket::Open),
86-
Token::Operand(Number::NaturalNumber(4)),
88+
Token::Operand(Number::NaturalNumber(BigInt::from(4u8))),
8789
Token::Operator(Operator::Sub),
88-
Token::Operand(Number::NaturalNumber(5)),
90+
Token::Operand(Number::NaturalNumber(BigInt::from(5u8))),
8991
Token::Bracket(Bracket::Close),
9092
])
9193
);
@@ -101,10 +103,10 @@ mod tests {
101103
Token::Operator(Operator::Add),
102104
Token::Bracket(Bracket::Open),
103105
Token::Operator(Operator::Sub),
104-
Token::Operand(Number::NaturalNumber(5)),
106+
Token::Operand(Number::NaturalNumber(BigInt::from(5u8))),
105107
Token::Operator(Operator::Mul),
106108
Token::Operator(Operator::Sub),
107-
Token::Operand(Number::NaturalNumber(5)),
109+
Token::Operand(Number::NaturalNumber(BigInt::from(5u8))),
108110
Token::Bracket(Bracket::Close),
109111
Token::Bracket(Bracket::Close),
110112
];
@@ -114,10 +116,10 @@ mod tests {
114116
Token::Bracket(Bracket::Open),
115117
Token::Bracket(Bracket::Open),
116118
Token::Operator(Operator::Une),
117-
Token::Operand(Number::NaturalNumber(5)),
119+
Token::Operand(Number::NaturalNumber(BigInt::from(5u8))),
118120
Token::Operator(Operator::Mul),
119121
Token::Operator(Operator::Une),
120-
Token::Operand(Number::NaturalNumber(5)),
122+
Token::Operand(Number::NaturalNumber(BigInt::from(5u8))),
121123
Token::Bracket(Bracket::Close),
122124
Token::Bracket(Bracket::Close),
123125
];

src/rpn_resolver.rs

+48-30
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use std::{collections::{HashMap, VecDeque}, rc::Rc, cell::RefCell, fmt::Display};
22
use crate::{
33
parser::Parser,
4-
token::{self, MathFunction, Number, Operator, Token, ZERO},
4+
token::{self, MathFunction, Number, Operator, Token},
55
};
66
use anyhow::anyhow;
77
use log::debug;
8+
use num::{BigInt, One, ToPrimitive, Zero};
89

910
static MALFORMED_ERR: &str = "Runtime Error: The mathematical expression is malformed.";
1011
static DIVISION_ZERO_ERR: &str = "Runtime error: Divide by zero.";
@@ -22,6 +23,7 @@ pub struct RpnResolver<'a> {
2223
}
2324

2425
impl RpnResolver<'_> {
26+
2527
/// Generates a new [`RpnResolver`] instance with borrowed heap
2628
///
2729
pub fn parse_with_borrowed_heap<'a>(
@@ -41,14 +43,18 @@ impl RpnResolver<'_> {
4143
/// This method evaluates the rpn expression stack
4244
///
4345
pub fn resolve(&mut self) -> anyhow::Result<Number> {
46+
47+
let zero: Number = Number::NaturalNumber(Zero::zero());
48+
let minus_one: Number = Number::NaturalNumber(BigInt::from(-1));
49+
4450
let mut result_stack: VecDeque<Number> = VecDeque::new();
4551

4652
let mut last_var_ref: Option<&str> = None;
4753

4854
for t in &self.rpn_expr {
4955
match t {
5056
Token::Operand(n) => {
51-
result_stack.push_back(*n);
57+
result_stack.push_back(n.clone());
5258
}
5359
Token::Operator(op) => {
5460
let right_value: Number = result_stack
@@ -60,23 +66,23 @@ impl RpnResolver<'_> {
6066
.pop_back()
6167
.ok_or_else(|| anyhow!("{} {}", MALFORMED_ERR, "Invalid Left Operand."))?
6268
} else {
63-
ZERO
69+
zero.clone()
6470
};
6571

6672
match op {
6773
Operator::Add => result_stack.push_back(left_value + right_value),
6874
Operator::Sub => result_stack.push_back(left_value - right_value),
6975
Operator::Mul => result_stack.push_back(left_value * right_value),
7076
Operator::Div => {
71-
if right_value == ZERO {
77+
if right_value == zero {
7278
return Err(anyhow!(DIVISION_ZERO_ERR));
7379
}
7480
left_value = Number::DecimalNumber(left_value.into());
7581
result_stack.push_back(left_value / right_value);
7682
}
7783
Operator::Pow => {
78-
if right_value < ZERO {
79-
if left_value == ZERO {
84+
if right_value < zero {
85+
if left_value == zero {
8086
return Err(anyhow!(DIVISION_ZERO_ERR));
8187
}
8288
left_value = Number::DecimalNumber(left_value.into());
@@ -86,24 +92,25 @@ impl RpnResolver<'_> {
8692
Operator::Eql => {
8793
if let Some(var) = last_var_ref {
8894
self.local_heap.borrow_mut()
89-
.insert(var.to_string(), right_value);
90-
debug!("Heap {:?}", self.local_heap);
95+
.insert(var.to_string(), right_value.clone());
96+
9197
result_stack.push_back(right_value);
9298
} else {
9399
return Err(anyhow!(NO_VARIABLE_ERR));
94100
}
95101
}
96102
Operator::Fac => {
97103
// factorial. Only for natural numbers
98-
let v = i32::from(right_value);
99-
if v<0 {
100-
println!("Warning: Factorial of a Negative or Decimal number has not been yet implemented.");
104+
let v = BigInt::from(right_value);
105+
if v.partial_cmp(&Zero::zero()) == Some(std::cmp::Ordering::Less) {
106+
eprintln!("Warning: Factorial of a Negative or Decimal number has not been yet implemented.");
101107
}
102-
result_stack.push_back(Number::NaturalNumber((1..=v).product()));
108+
let res = Self::factorial_helper(v);
109+
result_stack.push_back(Number::NaturalNumber(res));
103110
}
104111
Operator::Une => {
105112
//# unary neg
106-
result_stack.push_back(right_value * token::MINUS_ONE);
113+
result_stack.push_back(right_value * minus_one.clone());
107114
}
108115
}
109116
}
@@ -114,7 +121,7 @@ impl RpnResolver<'_> {
114121
let n = heap
115122
.get(*v)
116123
.unwrap_or(&Number::DecimalNumber(0.));
117-
result_stack.push_back(*n);
124+
result_stack.push_back(n.clone());
118125
}
119126
Token::Function(fun) => {
120127
let value: Number = result_stack
@@ -165,14 +172,13 @@ impl RpnResolver<'_> {
165172
let mut postfix_stack: VecDeque<Token> = VecDeque::new();
166173

167174
/* Scan the infix expression from left to right. */
168-
//infix_stack.iter().for_each(|t: &Token| {
169175
for t in infix_stack {
170176
match *t {
171177
/* If the token is an operand, add it to the output list. */
172-
Token::Operand(_) => postfix_stack.push_back(*t),
178+
Token::Operand(_) => postfix_stack.push_back(t.clone()),
173179

174180
/* If the token is a left parenthesis, push it on the stack. */
175-
Token::Bracket(token::Bracket::Open) => operators_stack.push(*t),
181+
Token::Bracket(token::Bracket::Open) => operators_stack.push(t.clone()),
176182

177183
/* If the token is a right parenthesis:
178184
Pop the stack and add operators to the output list until you encounter a left parenthesis.
@@ -194,52 +200,63 @@ impl RpnResolver<'_> {
194200
pop op2 off the stack, onto the output list;
195201
push op1 on the stack.*/
196202
Token::Operator(_op) => {
197-
let op1: Token<'_> = *t;
203+
let op1: Token<'_> = t.clone();
198204

199205
while !operators_stack.is_empty() {
200206
let op2: &Token = operators_stack.last().unwrap();
201207
match op2 {
202208
Token::Operator(_) => {
203-
if Token::compare_operator_priority(op1, *op2) {
204-
postfix_stack.push_back(operators_stack.pop().unwrap());
209+
if Token::compare_operator_priority(op1.clone(), op2.clone()) {
210+
postfix_stack.push_back(operators_stack.pop().expect("It should not happen."));
205211
} else {
206212
break;
207213
}
208214
},
209215
Token::Function(_) => {
210-
postfix_stack.push_back(operators_stack.pop().unwrap());
216+
postfix_stack.push_back(operators_stack.pop().expect("It should not happen."));
211217
}
212218
_ => break,
213219
}
214220
}
215-
operators_stack.push(op1);
221+
operators_stack.push(op1.clone());
216222
},
217223

218224
Token::Function(_) => {
219-
operators_stack.push(*t);
225+
operators_stack.push(t.clone());
220226
},
221227

222228
/* If the token is a variable, add it to the output list and to the local_heap with a default value*/
223229
Token::Variable(s) => {
224-
postfix_stack.push_back(*t);
230+
postfix_stack.push_back(t.clone());
225231
let s = s.to_lowercase();
226232
local_heap.borrow_mut().entry(s) // let's not override consts
227-
.or_insert(token::ZERO);
233+
.or_insert(Number::NaturalNumber(Zero::zero()));
228234
},
229235
}
230236
debug!("Inspecting... {} - OUT {} - OP - {}", *t, DisplayThisDeque(&postfix_stack), DisplayThatVec(&operators_stack));
231237
};
232238

233239
/* After all tokens are read, pop remaining operators from the stack and add them to the list. */
234240
operators_stack.reverse();
235-
postfix_stack.extend(operators_stack.iter());
241+
operators_stack.iter().for_each(|t| postfix_stack.push_back(t.clone()));
242+
//postfix_stack.pop_front()
243+
//postfix_stack.extend(operators_stack.iter());
236244

237245
debug!(
238246
"Inspecting... EOF - OUT {} - OP - {}", DisplayThisDeque(&postfix_stack), DisplayThatVec(&operators_stack)
239247
);
240248

241249
(postfix_stack, local_heap)
242250
}
251+
252+
fn factorial_helper(n: BigInt) -> BigInt {
253+
if n == Zero::zero(){
254+
One::one()
255+
} else {
256+
n.checked_mul(&RpnResolver::factorial_helper(n.checked_sub(&One::one()).expect("It should not happen")))
257+
.expect("It should not happen.")
258+
}
259+
}
243260
}
244261

245262
struct DisplayThatVec<'a>(&'a Vec<Token<'a>>);
@@ -259,19 +276,20 @@ impl Display for DisplayThisDeque<'_> {
259276

260277
#[cfg(test)]
261278
mod tests {
279+
use num_bigint::BigInt;
262280
use super::*;
263281
use crate::token::{Number, Operator};
264282

265283
#[test]
266284
fn test_reverse_polish_notation() {
267285
let a: Vec<Token> = vec![
268-
Token::Operand(Number::NaturalNumber(1)),
286+
Token::Operand(Number::NaturalNumber(BigInt::from(1u8))),
269287
Token::Operator(Operator::Add),
270-
Token::Operand(Number::NaturalNumber(2)),
288+
Token::Operand(Number::NaturalNumber(BigInt::from(2u8))),
271289
];
272290
let b: Vec<Token> = vec![
273-
Token::Operand(Number::NaturalNumber(1)),
274-
Token::Operand(Number::NaturalNumber(2)),
291+
Token::Operand(Number::NaturalNumber(BigInt::from(1u8))),
292+
Token::Operand(Number::NaturalNumber(BigInt::from(2u8))),
275293
Token::Operator(Operator::Add),
276294
];
277295
assert_eq!(

src/session.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
use std::{cell::RefCell, collections::HashMap, rc::Rc};
3+
use num_bigint::BigInt;
34
use crate::{rpn_resolver::RpnResolver, token::Number};
45

56
/// A [`Session`] is an object that holds a variable heap in the form of a [`HashMap`]
@@ -43,12 +44,10 @@ impl Session {
4344
/// Creates a Variables heap (name-value)
4445
///
4546
fn init_local_heap() -> HashMap<String, Number> {
46-
static PI: Number = Number::DecimalNumber(std::f64::consts::PI);
47-
static E: Number = Number::DecimalNumber(std::f64::consts::E);
4847

4948
let mut local_heap: HashMap<String, Number> = HashMap::new();
50-
local_heap.insert("pi".to_string(), PI);
51-
local_heap.insert("e".to_string(), E);
49+
local_heap.insert("pi".to_string(), Number::DecimalNumber(std::f64::consts::PI));
50+
local_heap.insert("e".to_string(), Number::DecimalNumber(std::f64::consts::E));
5251
local_heap
5352
}
5453

@@ -59,10 +58,10 @@ impl Session {
5958
/// session.set("foo", 42);
6059
/// ``
6160
///
62-
pub fn set(&self, key: &str, value: i32) {
61+
pub fn set(&self, key: &str, value: i64) {
6362
self.variable_heap
6463
.borrow_mut()
65-
.insert(key.to_string(), Number::NaturalNumber(value));
64+
.insert(key.to_string(), Number::NaturalNumber(BigInt::from(value)));
6665
}
6766

6867
/// Declares and saves a new float variable ([`Number::DecimalNumber`])

0 commit comments

Comments
 (0)