diff --git a/coverage/badges/flat.svg b/coverage/badges/flat.svg index c6b8852..3442f1c 100644 --- a/coverage/badges/flat.svg +++ b/coverage/badges/flat.svg @@ -1,6 +1,6 @@ - coverage: 83% + xmlns:xlink="http://www.w3.org/1999/xlink" width="96" height="20" role="img" aria-label="coverage: 87%"> + coverage: 87% @@ -16,8 +16,8 @@ coverage - - 83% + + 87% \ No newline at end of file diff --git a/coverage/badges/flat_square.svg b/coverage/badges/flat_square.svg index 2f89d3b..35eb4ef 100644 --- a/coverage/badges/flat_square.svg +++ b/coverage/badges/flat_square.svg @@ -1,13 +1,13 @@ - coverage: 83% + xmlns:xlink="http://www.w3.org/1999/xlink" width="96" height="20" role="img" aria-label="coverage: 87%"> + coverage: 87% coverage - 83% + 87% \ No newline at end of file diff --git a/coverage/badges/for_the_badge.svg b/coverage/badges/for_the_badge.svg index a667c47..3622454 100644 --- a/coverage/badges/for_the_badge.svg +++ b/coverage/badges/for_the_badge.svg @@ -1,13 +1,13 @@ - COVERAGE: 83% + xmlns:xlink="http://www.w3.org/1999/xlink" width="142.5" height="28" role="img" aria-label="COVERAGE: 87%"> + COVERAGE: 87% COVERAGE - 83% + 87% \ No newline at end of file diff --git a/coverage/badges/plastic.svg b/coverage/badges/plastic.svg index 5a12a63..5e6bccc 100644 --- a/coverage/badges/plastic.svg +++ b/coverage/badges/plastic.svg @@ -1,6 +1,6 @@ - coverage: 83% + xmlns:xlink="http://www.w3.org/1999/xlink" width="96" height="18" role="img" aria-label="coverage: 87%"> + coverage: 87% @@ -18,8 +18,8 @@ coverage - - 83% + + 87% \ No newline at end of file diff --git a/coverage/badges/social.svg b/coverage/badges/social.svg index 074592f..95ea542 100644 --- a/coverage/badges/social.svg +++ b/coverage/badges/social.svg @@ -1,6 +1,6 @@ - Coverage: 83% + xmlns:xlink="http://www.w3.org/1999/xlink" width="99" height="20" role="img" aria-label="Coverage: 87%"> + Coverage: 87% @@ -20,8 +20,8 @@ Coverage - - 83% + + 87% \ No newline at end of file diff --git a/coverage/coverage.json b/coverage/coverage.json index f7e134b..602512a 100644 --- a/coverage/coverage.json +++ b/coverage/coverage.json @@ -1 +1 @@ -{"schemaVersion":1,"label":"coverage","message":"83%","color":"yellow"} \ No newline at end of file +{"schemaVersion":1,"label":"coverage","message":"87%","color":"yellow"} \ No newline at end of file diff --git a/coverage/index.html b/coverage/index.html index 64fcdbd..779b8ab 100644 --- a/coverage/index.html +++ b/coverage/index.html @@ -15,7 +15,7 @@

Lines

- 83.88 %

+ 87.86 %

@@ -23,7 +23,7 @@

Functions

- 89.01 %

+ 89.9 %

@@ -75,21 +75,21 @@ - 88.89% + 92.81% - - 88.89% + + 92.81% - - 488 / 549 + + 542 / 584 - 90.91% - 80 / 88 + 91.67% + 88 / 96 0 0 / 0 @@ -98,7 +98,7 @@ diff --git a/coverage/src/index.html b/coverage/src/index.html index 3832559..d5752d4 100644 --- a/coverage/src/index.html +++ b/coverage/src/index.html @@ -98,7 +98,7 @@ diff --git a/coverage/src/logic/calculator.rs.html b/coverage/src/logic/calculator.rs.html index db33769..713e9e2 100644 --- a/coverage/src/logic/calculator.rs.html +++ b/coverage/src/logic/calculator.rs.html @@ -14,8 +14,8 @@

Lines

-

- 85.33 %

+

+ 96.26 %

@@ -23,7 +23,7 @@

Functions

- 100 %

+ 100 %

@@ -499,7 +499,7 @@
- 8 + 12
    pub fn new() -> Calculator {
@@ -512,7 +512,7 @@
- 8 + 12
        Calculator {
@@ -525,7 +525,7 @@
- 8 + 12
            variables: HashMap::new(),
@@ -538,7 +538,7 @@
- 8 + 12
        }
@@ -551,7 +551,7 @@
- 8 + 12
    }
@@ -603,7 +603,7 @@
- 2 + 8
    pub fn calculate_infix(&mut self, input: &str) -> Result<String, String> {
@@ -616,7 +616,7 @@
- 2 + 8

@@ -629,7 +629,7 @@
             
- 2 + 8
        let mut eq_position = None;
@@ -668,7 +668,7 @@
- 12 + 36
        for (i, c) in input.chars().enumerate() {
@@ -681,7 +681,7 @@
- 12 + 36
            if c == '=' {
@@ -693,11 +693,11 @@ 51
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 5
-
-
                eq_position = Some(i);
+
+
                eq_position = Some(i);
52
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 5
-
-
                break;
+
+
                break;
- 12 + 31
            }
@@ -772,7 +772,7 @@
- 2 + 8
        let (variable, input) = if let Some(i) = eq_position {
@@ -784,11 +784,11 @@ 58
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 5
-
-
            (Some(tokenize(&input[..i])?), &input[i + 1..])
+
+
            (Some(tokenize(&input[..i])?), &input[i + 1..])
- 2 + 3
            (None, input)
@@ -837,7 +837,7 @@
- 2 + 8
        let tokens = tokenize(input)?;
@@ -850,7 +850,7 @@
- 2 + 8
        let postfix = shunting_yard(tokens)?;
@@ -863,7 +863,7 @@
- 1 + 7
        let result = self.eval_postfix(postfix)?;
@@ -915,7 +915,7 @@
- 1 + 7
        if let Some(var_list) = variable {
@@ -953,11 +953,11 @@ 71
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 5
-
-
            if var_list.len() > 1 {
+
+
            if var_list.len() > 1 {
72
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 1
-
-
                return Err("Too many tokens before '='".to_string());
+
+
                return Err("Too many tokens before '='".to_string());
73
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 4
-
-
            }
+
+
            }
74
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 4
-
-
            // if expression starts with =
+
+
            // if expression starts with =
75
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 4
-
-
            // (e.g. "= 1 + 1")
+
+
            // (e.g. "= 1 + 1")
76
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 4
-
-
            if var_list.is_empty() {
+
+
            if var_list.is_empty() {
77
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 1
-
-
                return Err("Variable required before '='".to_string());
+
+
                return Err("Variable required before '='".to_string());
78
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 3
-
-
            }
+
+
            }
82
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 3
-
-
            if let Variable(variable) = &var_list[0] {
+
+
            if let Variable(variable) = &var_list[0] {
83
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 2
-
-
                self.variables.insert(variable.to_string(), result);
+
+
                self.variables.insert(variable.to_string(), result);
84
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 2
-
-
            } else {
+
+
            } else {
85
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 1
-
-
                return Err("Malformed input before '='".to_string());
+
+
                return Err("Malformed input before '='".to_string());
- 1 + 2
        }
@@ -1175,7 +1175,7 @@
- 1 + 4
        Ok(format!("{result}"))
@@ -1188,7 +1188,7 @@
- 2 + 8
    }
@@ -1240,7 +1240,7 @@
- 7 + 13
    fn eval_postfix(&self, input: Vec<Token>) -> Result<f64, String> {
@@ -1253,7 +1253,7 @@
- 7 + 13
        let mut stack = Vec::new();
@@ -1266,7 +1266,7 @@
- 28 + 52
        for token in input {
@@ -1279,7 +1279,7 @@
- 9 + 15
            match token {
@@ -1292,7 +1292,7 @@
- 14 + 22
                Number(num) => stack.push(num),
@@ -1357,7 +1357,7 @@
- 9 + 15
                Op(op) => {
@@ -1370,7 +1370,7 @@
- 9 + 15
                    let a = stack.pop().ok_or("Too many operators")?;
@@ -1383,7 +1383,7 @@
- 8 + 14
                    let b = stack.pop().ok_or("Too many operators")?;
@@ -1396,7 +1396,7 @@
- 7 + 13
                    match operate(b, a, op) {
@@ -1409,7 +1409,7 @@
- 7 + 13
                        Ok(result) => stack.push(result),
@@ -1486,11 +1486,11 @@ 112
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 4
-
-
                Variable(var) => {
+
+
                Variable(var) => {
113
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 4
-
-
                    if let Some(&val) = self.variables.get(&var) {
+
+
                    if let Some(&val) = self.variables.get(&var) {
114
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 4
-
-
                        stack.push(val);
+
+
                        stack.push(val);
115
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 4
-
-
                    } else {
+
+
                    } else {
- 5 + 11
        let res = stack.pop().ok_or("Too many operators")?;
@@ -1643,7 +1643,7 @@
- 5 + 11
        if !stack.is_empty() {
@@ -1669,7 +1669,7 @@
- 4 + 10
        }
@@ -1682,7 +1682,7 @@
- 4 + 10
        Ok(res)
@@ -1695,7 +1695,7 @@
- 7 + 13
    }
@@ -1916,7 +1916,7 @@
- 13 + 19
fn operate(a: f64, b: f64, op: Operator) -> Result<f64, String> {
@@ -1929,7 +1929,7 @@
- 13 + 19
    use crate::logic::enums::Operator::*;
@@ -1942,7 +1942,7 @@
- 13 + 19
    // neither a or b should ever be NaN or infinite (should be caught beforehand), 
@@ -1955,7 +1955,7 @@
- 13 + 19
    // but in case it happens anyway, return an error
@@ -1968,7 +1968,7 @@
- 13 + 19
    if a.is_nan() || b.is_nan() {
@@ -1994,7 +1994,7 @@
- 13 + 19
    }
@@ -2007,7 +2007,7 @@
- 13 + 19
    if a.is_infinite() || b.is_infinite() {
@@ -2033,7 +2033,7 @@
- 13 + 19
    }
@@ -2046,7 +2046,7 @@
- 13 + 19

@@ -2059,7 +2059,7 @@
             
- 13 + 19
    match op {
@@ -2072,7 +2072,7 @@
- 4 + 10
        Plus => Ok(a + b),
@@ -2267,7 +2267,7 @@
- 13 + 19
}
@@ -4010,6 +4010,474 @@
+
+
+

+            
+
+
+ 307 +
+
+ 1 +
+
+
    #[test]
+
+
+
+ 308 +
+
+ 1 +
+
+
    fn error_when_extra_before_equals() {
+
+
+
+ 309 +
+
+ 1 +
+
+
        let mut calculator = Calculator::new();
+
+
+
+ 310 +
+
+ 1 +
+
+
        let res = calculator.calculate_infix("a b = 1");
+
+
+
+ 311 +
+
+ 1 +
+
+

+            
+
+
+ 312 +
+
+ 1 +
+
+
        assert!(res.is_err());
+
+
+
+ 313 +
+
+ 1 +
+
+
    }
+
+
+
+ 314 +
+
+ +
+
+

+            
+
+
+ 315 +
+
+ 1 +
+
+
    #[test]
+
+
+
+ 316 +
+
+ 1 +
+
+
    fn error_equals_without_variable() {
+
+
+
+ 317 +
+
+ 1 +
+
+
        let mut calculator = Calculator::new();
+
+
+
+ 318 +
+
+ 1 +
+
+
        let res = calculator.calculate_infix("= 1 + 2");
+
+
+
+ 319 +
+
+ 1 +
+
+

+            
+
+
+ 320 +
+
+ 1 +
+
+
        assert!(res.is_err());
+
+
+
+ 321 +
+
+ 1 +
+
+
    }
+
+
+
+ 322 +
+
+ +
+
+

+            
+
+
+ 323 +
+
+ 1 +
+
+
    #[test]
+
+
+
+ 324 +
+
+ 1 +
+
+
    fn correct_variables_stored_and_returned() {
+
+
+
+ 325 +
+
+ 1 +
+
+
        let mut calculator = Calculator::new();
+
+
+
+ 326 +
+
+ 1 +
+
+
        let res = calculator.calculate_infix("a = 1 + 2");
+
+
+
+ 327 +
+
+ 1 +
+
+
        assert_eq!(res.unwrap(), "3");
+
+
+
+ 328 +
+
+ +
+
+

+            
+
+
+ 329 +
+
+ 1 +
+
+
        let res = calculator.calculate_infix("b = 1 + a");
+
+
+
+ 330 +
+
+ 1 +
+
+
        assert_eq!(res.unwrap(), "4");
+
+
+
+ 331 +
+
+ +
+
+

+            
+
+
+ 332 +
+
+ 1 +
+
+
        let res = calculator.calculate_infix("b + a + a");
+
+
+
+ 333 +
+
+ 1 +
+
+
        assert_eq!(res.unwrap(), "10");
+
+
+
+ 334 +
+
+ 1 +
+
+
    }
+
+
+
+ 335 +
+
+ +
+
+

+            
+
+
+ 336 +
+
+ 1 +
+
+
    #[test]
+
+
+
+ 337 +
+
+ 1 +
+
+
    fn error_bad_variable_input() {
+
+
+
+ 338 +
+
+ 1 +
+
+
        let mut calculator = Calculator::new();
+
+
+
+ 339 +
+
+ 1 +
+
+
        let res = calculator.calculate_infix("* = 1 + 2");
+
+
+
+ 340 +
+
+ 1 +
+
+
        assert!(res.is_err());
+
+
+
+ 341 +
+
+ 1 +
+
+
    }
+
+
+
+ 342 +
+
+
}
@@ -4017,7 +4485,7 @@
-

Date: 2022-03-04 19:37

+

Date: 2022-03-13 19:09

diff --git a/coverage/src/logic/enums.rs.html b/coverage/src/logic/enums.rs.html index d7b8ed6..6c0f698 100644 --- a/coverage/src/logic/enums.rs.html +++ b/coverage/src/logic/enums.rs.html @@ -278,7 +278,7 @@
- 25 + 32
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -1625,7 +1625,7 @@
-

Date: 2022-03-04 19:37

+

Date: 2022-03-13 19:09

diff --git a/coverage/src/logic/index.html b/coverage/src/logic/index.html index 4e9ea62..3a528dc 100644 --- a/coverage/src/logic/index.html +++ b/coverage/src/logic/index.html @@ -14,8 +14,8 @@

Lines

-

- 88.89 %

+

+ 92.81 %

@@ -23,7 +23,7 @@

Functions

- 90.91 %

+ 91.67 %

@@ -51,21 +51,21 @@ - 85.33% + 96.26% - - 85.33% + + 96.26% - - 157 / 184 + + 206 / 214 100% - 32 / 32 + 40 / 40 0 0 / 0 @@ -124,16 +124,16 @@ - 86.62% + 87.04% - 86.62% + 87.04% - 136 / 157 + 141 / 162 94.74% @@ -146,7 +146,7 @@
-

Date: 2022-03-04 19:37

+

Date: 2022-03-13 19:09

diff --git a/coverage/src/logic/shunting_yard.rs.html b/coverage/src/logic/shunting_yard.rs.html index 49fa924..ba5d504 100644 --- a/coverage/src/logic/shunting_yard.rs.html +++ b/coverage/src/logic/shunting_yard.rs.html @@ -226,7 +226,7 @@
- 14 + 21
fn precedence(op: Operator) -> Option<u8> {
@@ -239,7 +239,7 @@
- 14 + 21
    match op {
@@ -252,7 +252,7 @@
- 7 + 14
        Plus | Minus => Some(2),
@@ -317,7 +317,7 @@
- 14 + 21
}
@@ -525,7 +525,7 @@
- 9 + 15
pub fn shunting_yard(input: Vec<Token>) -> Result<Vec<Token>, String> {
@@ -538,7 +538,7 @@
- 9 + 15
    let mut output = Vec::new();
@@ -551,7 +551,7 @@
- 9 + 15
    let mut operators = Vec::new();
@@ -564,7 +564,7 @@
- 9 + 15

@@ -577,7 +577,7 @@
             
- 9 + 15
    // only one operator can occur before a number
@@ -590,7 +590,7 @@
- 9 + 15
    // "1 + 1" is ok, "1 ++ 1" is not
@@ -603,7 +603,7 @@
- 9 + 15
    let mut is_operator_time = false;
@@ -629,7 +629,7 @@
- 42 + 66
    for token in input {
@@ -642,7 +642,7 @@
- 16 + 22
        match token {
@@ -876,7 +876,7 @@
- 12 + 18
            Op(op) => {
@@ -889,7 +889,7 @@
- 12 + 18
                if !is_operator_time {
@@ -915,7 +915,7 @@
- 11 + 17
                }
@@ -928,7 +928,7 @@
- 11 + 17
                is_operator_time = false;
@@ -941,7 +941,7 @@
- 11 + 17
                if let Some(p1) = precedence(op) {
@@ -954,7 +954,7 @@
- 12 + 18
                    while !operators.is_empty() {
@@ -967,7 +967,7 @@
- 5 + 6
                        let last_operator = operators[operators.len() - 1];
@@ -980,7 +980,7 @@
- 5 + 6
                        if last_operator == Lparen {
@@ -1006,7 +1006,7 @@
- 3 + 4
                        }
@@ -1032,7 +1032,7 @@
- 3 + 4
                        if let Some(p2) = precedence(last_operator) {
@@ -1045,7 +1045,7 @@
- 3 + 4
                            if p2 <= p1 {
@@ -1058,7 +1058,7 @@
- 2 + 3
                                break;
@@ -1136,7 +1136,7 @@
- 11 + 17
                    operators.push(op);
@@ -1188,7 +1188,7 @@
- 20 + 32
                if is_operator_time {
@@ -1214,7 +1214,7 @@
- 19 + 31
                }
@@ -1227,7 +1227,7 @@
- 19 + 31
                is_operator_time = true;
@@ -1240,7 +1240,7 @@
- 19 + 31
                output.push(token);
@@ -1305,7 +1305,7 @@
- 12 + 24
    while let Some(op) = operators.pop() {
@@ -1318,7 +1318,7 @@
- 7 + 13
        if op == Lparen {
@@ -1344,7 +1344,7 @@
- 6 + 12
        }
@@ -1357,7 +1357,7 @@
- 6 + 12
        output.push(Op(op));
@@ -1396,7 +1396,7 @@
- 5 + 11
    Ok(output)
@@ -1409,7 +1409,7 @@
- 9 + 15
}
@@ -2717,7 +2717,7 @@
-

Date: 2022-03-04 19:37

+

Date: 2022-03-13 19:09

diff --git a/coverage/src/logic/tokenize.rs.html b/coverage/src/logic/tokenize.rs.html index 5e4173d..b65e2be 100644 --- a/coverage/src/logic/tokenize.rs.html +++ b/coverage/src/logic/tokenize.rs.html @@ -15,7 +15,7 @@

Lines

- 86.62 %

+ 87.04 %

@@ -265,7 +265,7 @@
- 8 + 19
pub fn tokenize(input: &str) -> Result<Vec<Token>, String> {
@@ -278,7 +278,7 @@
- 8 + 19
    let mut output = Vec::new();
@@ -291,7 +291,7 @@
- 8 + 19

@@ -304,7 +304,7 @@
             
- 8 + 19
    let mut chars = input.chars().peekable();
@@ -330,7 +330,7 @@
- 34 + 84
    loop {
@@ -343,7 +343,7 @@
- 34 + 84
        let c = chars.next();
@@ -356,7 +356,7 @@
- 34 + 84
        if c.is_none() {
@@ -369,7 +369,7 @@
- 7 + 18
            break;
@@ -382,7 +382,7 @@
- 27 + 66
        }
@@ -395,7 +395,7 @@
- 27 + 66
        let c = c.unwrap();
@@ -447,7 +447,7 @@
- 27 + 66
        let negative_number = if c == '-' {
@@ -551,7 +551,7 @@
- 27 + 66
            false
@@ -603,7 +603,7 @@
- 27 + 66
        if c.is_digit(10) || negative_number {
@@ -616,7 +616,7 @@
- 7 + 15
            let mut num_string = String::new();
@@ -629,7 +629,7 @@
- 7 + 15
            num_string.push(c);
@@ -642,7 +642,7 @@
- 7 + 15
            let mut found_decimal = false;
@@ -694,7 +694,7 @@
- 9 + 17
            while let Some(&c) = chars.peek() {
@@ -707,7 +707,7 @@
- 5 + 9
                if c.is_digit(10) {
@@ -733,7 +733,7 @@
- 4 + 8
                } else if c == '.' {
@@ -824,7 +824,7 @@
- 3 + 7
                    break;
@@ -889,7 +889,7 @@
- 7 + 15
            let &num = &num_string.parse::<f64>().unwrap();
@@ -902,7 +902,7 @@
- 7 + 15
            output.push(Number(num));
@@ -915,7 +915,7 @@
- 7 + 15
            continue;
@@ -928,7 +928,7 @@
- 20 + 51
        }
@@ -967,7 +967,7 @@
- 20 + 51
        if let Some(op) = get_operator(c) {
@@ -980,7 +980,7 @@
- 9 + 16
            output.push(Op(op));
@@ -993,7 +993,7 @@
- 9 + 16
            continue;
@@ -1006,7 +1006,7 @@
- 11 + 35
        }
@@ -1019,7 +1019,7 @@
- 11 + 35

@@ -1032,7 +1032,7 @@
             
- 11 + 35
        // ignore whitespace. This way "1+1" and "1 + 1" are equivalent
@@ -1045,7 +1045,7 @@
- 11 + 35
        if c.is_whitespace() {
@@ -1058,7 +1058,7 @@
- 8 + 24
            continue;
@@ -1071,7 +1071,7 @@
- 3 + 11
        }
@@ -1084,7 +1084,7 @@
- 3 + 11

@@ -1097,7 +1097,7 @@
             
- 3 + 11
        // if c is a letter, it can either be a variable name or a function
@@ -1110,7 +1110,7 @@
- 3 + 11
        // if the following character is a left parenthesis, it's a function
@@ -1123,7 +1123,7 @@
- 3 + 11
        if c.is_alphabetic() {
@@ -1136,7 +1136,7 @@
- 2 + 10
            let mut var_string = String::new();
@@ -1149,7 +1149,7 @@
- 2 + 10
            var_string.push(c);
@@ -1162,7 +1162,7 @@
- 2 + 10

@@ -1175,7 +1175,7 @@
             
- 2 + 10
            let mut is_function = false;
@@ -1188,10 +1188,10 @@
- 9 + 10
-
            while let Some(&c) = chars.peek() {
+
            let mut found_whitespace = false;
- 8 + 23
-
                if c.is_alphanumeric() {
+
            while let Some(&c) = chars.peek() {
- 6 + 17
-
                    var_string.push(c);
+
                if c.is_alphanumeric() {
92
- 6 + class="column is-1 is-narrow p-0 has-text-centered has-text-white has-background-white"> +
-
-
                } else if c.is_whitespace() {
+
+

             
93
- 1 + class="column is-1 is-narrow p-0 has-text-centered has-text-white has-background-white"> +
-
-
                } else if c == '(' {
+
+
                    // 1 + a b + 2 is not valid syntax (`a b` is two variables after each other) 
94
+ class="column is-1 is-narrow p-0 has-text-centered has-text-white has-background-white">
-
-
                    is_function = true;
+
+
                    // have to check here (instead of just forbidding all whitespace) because a
95
+ class="column is-1 is-narrow p-0 has-text-centered has-text-white has-background-white">
-
-
                    break;
+
+
                    // function can have spaces between the characters and the parentheses:
-
                } else {
+
                    // sin (2) == sin(2)
- 1 + 7
-
                    break;
+
                    if found_whitespace {
98
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 1
-
-
                }
+
+
                        break;
- 7 + 6
-
                chars.next();
+
                    }
100
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 6
-
-
            }
+
+
                    var_string.push(c);
- 2 + 10
-
            if is_function {
+
                } else if c.is_whitespace() {
102
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 7
-
-

+            
+
                    found_whitespace = true;
103
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 7
-
-
                if let Some(fun) = get_function(&var_string) {
+
+
                } else if c == '(' {
-
                    output.push(Op(Func(fun)));
+
                    is_function = true;
-
                } else {
+
                    break;
106
+ class="column is-1 is-narrow p-0 has-text-centered has-text-white has-background-white">
-
-
                    return Err(format!("Unknown function: {var_string}"));
+
+
                } else {
107
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 3
-
-
                }
+
+
                    break;
108
- 2 + class="column is-1 is-narrow p-0 has-text-centered has-text-white has-background-white"> +
-
-
            } else {
+
+
                }
- 2 + 13
-
                output.push(Variable(var_string));
+
                chars.next();
110
- 2 + class="column is-1 is-narrow p-0 has-text-centered has-text-white has-background-white"> +
-
-
            }
+
+
            }
- 2 + 10
-
            continue;
+
            if is_function {
112
- 1 + class="column is-1 is-narrow p-0 has-text-centered has-text-white has-background-white"> +
-
-
        }
+
+

             
113
- 1 + class="column is-1 is-narrow p-0 has-text-centered has-text-danger-light has-background-danger"> +
-
-

+            
+
                if let Some(fun) = get_function(&var_string) {
114
- 1 + class="column is-1 is-narrow p-0 has-text-centered has-text-danger-light has-background-danger"> +
-
-
        if c == '=' {
+
+
                    output.push(Op(Func(fun)));
-
            output.push(Op(Operator::Equals));
+
                } else {
-
            continue;
+
                    return Err(format!("Unknown function: {var_string}"));
117
- 1 + class="column is-1 is-narrow p-0 has-text-centered has-text-white has-background-white"> +
-
-
        }
+
+
                }
- 1 + 10
-
        return Err(format!("Unknown character, or incorrectly placed: {c}"));
+
            } else {
119
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 10
-
-
    }
+
+
                output.push(Variable(var_string));
- 7 + 10
-
    Ok(output)
+
            }
- 8 + 10
-
}
+
            continue;
122
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 1
-
-

+            
+
        }
123
- + class="column is-1 is-narrow p-0 has-text-centered has-text-success-light has-background-success"> + 1
-
-
/// Return true if `c` is one of the defined mathematical operators
+
+

             
- 32 + 1
-
fn get_operator(c: char) -> Option<Operator> {
+
        if c == '=' {
125
- 32 + class="column is-1 is-narrow p-0 has-text-centered has-text-danger-light has-background-danger"> +
-
-
    use self::Operator::*;
+
+
            output.push(Op(Operator::Equals));
126
- 32 + class="column is-1 is-narrow p-0 has-text-centered has-text-danger-light has-background-danger"> +
-
-
    match c {
+
+
            continue;
- 5 + 1
-
        '+' => Some(Plus),
+
        }
-
        '-' => Some(Minus),
+
        return Err(format!("Unknown character, or incorrectly placed: {c}"));
129
- 2 + class="column is-1 is-narrow p-0 has-text-centered has-text-white has-background-white"> +
-
-
        '/' => Some(Div),
+
+
    }
- 3 + 18
-
        '*' => Some(Mul),
+
    Ok(output)
- 1 + 19
-
        '^' => Some(Pow),
+
}
132
+
+ +
+
+

+            
+
+
+ 133 +
+
+ +
+
+
/// Return true if `c` is one of the defined mathematical operators
+
+
+
+ 134 +
+
+ 63 +
+
+
fn get_operator(c: char) -> Option<Operator> {
+
+
+
+ 135 +
+
+ 63 +
+
+
    use self::Operator::*;
+
+
+
+ 136 +
+
+ 63 +
+
+
    match c {
+
+
+
+ 137 +
+
+ 11 +
+
+
        '+' => Some(Plus),
+
+
+
+ 138 +
+
+ 1 +
+
+
        '-' => Some(Minus),
+
+
+
+ 139 +
+
+ 2 +
+
+
        '/' => Some(Div),
+
+
+
+ 140 +
+
+ 4 +
+
+
        '*' => Some(Mul),
+
+
+
+ 141 +
+
+ 1 +
+
+
        '^' => Some(Pow),
+
+
+
+ 142 +
2 @@ -1755,8 +1885,8 @@
- 133 + id="143"> + 143
@@ -1768,12 +1898,12 @@
- 134 + id="144"> + 144
- 16 + 40
        _ => None
@@ -1781,8 +1911,8 @@
- 135 + id="145"> + 145
@@ -1794,12 +1924,12 @@
- 136 + id="146"> + 146
- 32 + 63
}
@@ -1807,8 +1937,8 @@
- 137 + id="147"> + 147
@@ -1820,8 +1950,8 @@
- 138 + id="148"> + 148
@@ -1833,8 +1963,8 @@
- 139 + id="149"> + 149
@@ -1846,8 +1976,8 @@
- 140 + id="150"> + 150
@@ -1859,8 +1989,8 @@
- 141 + id="151"> + 151
@@ -1872,8 +2002,8 @@
- 142 + id="152"> + 152
@@ -1885,8 +2015,8 @@
- 143 + id="153"> + 153
@@ -1898,8 +2028,8 @@
- 144 + id="154"> + 154
@@ -1911,8 +2041,8 @@
- 145 + id="155"> + 155
@@ -1924,8 +2054,8 @@
- 146 + id="156"> + 156
@@ -1937,8 +2067,8 @@
- 147 + id="157"> + 157
@@ -1950,8 +2080,8 @@
- 148 + id="158"> + 158
@@ -1963,8 +2093,8 @@
- 149 + id="159"> + 159
@@ -1976,8 +2106,8 @@
- 150 + id="160"> + 160
@@ -1989,8 +2119,8 @@
- 151 + id="161"> + 161
@@ -2002,8 +2132,8 @@
- 152 + id="162"> + 162
@@ -2015,8 +2145,8 @@
- 153 + id="163"> + 163
@@ -2028,8 +2158,8 @@
- 154 + id="164"> + 164
@@ -2041,8 +2171,8 @@
- 155 + id="165"> + 165
@@ -2054,8 +2184,8 @@
- 156 + id="166"> + 166
@@ -2067,8 +2197,8 @@
- 157 + id="167"> + 167
@@ -2080,8 +2210,8 @@
- 158 + id="168"> + 168
@@ -2093,8 +2223,8 @@
- 159 + id="169"> + 169
@@ -2106,8 +2236,8 @@
- 160 + id="170"> + 170
@@ -2119,8 +2249,8 @@
- 161 + id="171"> + 171
@@ -2132,8 +2262,8 @@
- 162 + id="172"> + 172
@@ -2145,8 +2275,8 @@
- 163 + id="173"> + 173
@@ -2158,8 +2288,8 @@
- 164 + id="174"> + 174
@@ -2171,8 +2301,8 @@
- 165 + id="175"> + 175
@@ -2184,8 +2314,8 @@
- 166 + id="176"> + 176
@@ -2197,8 +2327,8 @@
- 167 + id="177"> + 177
@@ -2210,8 +2340,8 @@
- 168 + id="178"> + 178
@@ -2223,8 +2353,8 @@
- 169 + id="179"> + 179
@@ -2236,8 +2366,8 @@
- 170 + id="180"> + 180
@@ -2249,8 +2379,8 @@
- 171 + id="181"> + 181
@@ -2262,8 +2392,8 @@
- 172 + id="182"> + 182
@@ -2275,8 +2405,8 @@
- 173 + id="183"> + 183
@@ -2288,8 +2418,8 @@
- 174 + id="184"> + 184
@@ -2301,8 +2431,8 @@
- 175 + id="185"> + 185
@@ -2314,8 +2444,8 @@
- 176 + id="186"> + 186
@@ -2327,8 +2457,8 @@
- 177 + id="187"> + 187
@@ -2340,8 +2470,8 @@
- 178 + id="188"> + 188
@@ -2353,8 +2483,8 @@
- 179 + id="189"> + 189
@@ -2366,8 +2496,8 @@
- 180 + id="190"> + 190
@@ -2379,8 +2509,8 @@
- 181 + id="191"> + 191
@@ -2392,8 +2522,8 @@
- 182 + id="192"> + 192
@@ -2405,8 +2535,8 @@
- 183 + id="193"> + 193
@@ -2418,8 +2548,8 @@
- 184 + id="194"> + 194
@@ -2431,8 +2561,8 @@
- 185 + id="195"> + 195
@@ -2444,8 +2574,8 @@
- 186 + id="196"> + 196
@@ -2457,8 +2587,8 @@
- 187 + id="197"> + 197
@@ -2470,8 +2600,8 @@
- 188 + id="198"> + 198
@@ -2483,8 +2613,8 @@
- 189 + id="199"> + 199
@@ -2496,8 +2626,8 @@
- 190 + id="200"> + 200
@@ -2509,8 +2639,8 @@
- 191 + id="201"> + 201
@@ -2522,8 +2652,8 @@
- 192 + id="202"> + 202
@@ -2535,8 +2665,8 @@
- 193 + id="203"> + 203
@@ -2548,8 +2678,8 @@
- 194 + id="204"> + 204
@@ -2561,8 +2691,8 @@
- 195 + id="205"> + 205
@@ -2574,8 +2704,8 @@
- 196 + id="206"> + 206
@@ -2587,8 +2717,8 @@
- 197 + id="207"> + 207
@@ -2600,8 +2730,8 @@
- 198 + id="208"> + 208
@@ -2613,8 +2743,8 @@
- 199 + id="209"> + 209
@@ -2626,8 +2756,8 @@
- 200 + id="210"> + 210
@@ -2639,8 +2769,8 @@
- 201 + id="211"> + 211
@@ -2652,8 +2782,8 @@
- 202 + id="212"> + 212
@@ -2665,8 +2795,8 @@
- 203 + id="213"> + 213
@@ -2678,8 +2808,8 @@
- 204 + id="214"> + 214
@@ -2691,8 +2821,8 @@
- 205 + id="215"> + 215
@@ -2704,8 +2834,8 @@
- 206 + id="216"> + 216
@@ -2717,8 +2847,8 @@
- 207 + id="217"> + 217
@@ -2730,8 +2860,8 @@
- 208 + id="218"> + 218
@@ -2743,8 +2873,8 @@
- 209 + id="219"> + 219
@@ -2756,8 +2886,8 @@
- 210 + id="220"> + 220
@@ -2769,8 +2899,8 @@
- 211 + id="221"> + 221
@@ -2782,8 +2912,8 @@
- 212 + id="222"> + 222
@@ -2795,8 +2925,8 @@
- 213 + id="223"> + 223
@@ -2808,8 +2938,8 @@
- 214 + id="224"> + 224
@@ -2821,8 +2951,8 @@
- 215 + id="225"> + 225
@@ -2834,8 +2964,8 @@
- 216 + id="226"> + 226
@@ -2847,8 +2977,8 @@
- 217 + id="227"> + 227
@@ -2860,8 +2990,8 @@
- 218 + id="228"> + 228
@@ -2873,8 +3003,8 @@
- 219 + id="229"> + 229
@@ -2886,8 +3016,8 @@
- 220 + id="230"> + 230
@@ -2899,8 +3029,8 @@
- 221 + id="231"> + 231
@@ -2912,8 +3042,8 @@
- 222 + id="232"> + 232
@@ -2925,8 +3055,8 @@
- 223 + id="233"> + 233
@@ -2938,8 +3068,8 @@
- 224 + id="234"> + 234
@@ -2951,8 +3081,8 @@
- 225 + id="235"> + 235
@@ -2964,8 +3094,8 @@
- 226 + id="236"> + 236
@@ -2977,8 +3107,8 @@
- 227 + id="237"> + 237
@@ -2990,7 +3120,7 @@
-

Date: 2022-03-04 19:37

+

Date: 2022-03-13 19:09

diff --git a/coverage/src/main.rs.html b/coverage/src/main.rs.html index ad55474..916a78c 100644 --- a/coverage/src/main.rs.html +++ b/coverage/src/main.rs.html @@ -143,7 +143,7 @@
-

Date: 2022-03-04 19:37

+

Date: 2022-03-13 19:09

diff --git a/coverage/src/ui.rs.html b/coverage/src/ui.rs.html index aa7c48d..d1c77af 100644 --- a/coverage/src/ui.rs.html +++ b/coverage/src/ui.rs.html @@ -650,7 +650,7 @@
-

Date: 2022-03-04 19:37

+

Date: 2022-03-13 19:09

diff --git a/src/logic/calculator.rs b/src/logic/calculator.rs index 4cf1b39..5e33154 100644 --- a/src/logic/calculator.rs +++ b/src/logic/calculator.rs @@ -2,7 +2,6 @@ use super::shunting_yard; use super::tokenize; use std::collections::HashMap; use super::enums::Token::{self, Op, Variable, Number}; -// use super::enums::Number; use super::enums::Operator::{self, *}; /// Struct for keeping track of history and variables, and performing calculations. @@ -33,6 +32,8 @@ pub struct Calculator { } impl Calculator { + + /// Creates a new `Calculator` object and initializes its variable table. pub fn new() -> Calculator { Calculator { variables: HashMap::new(), @@ -41,6 +42,13 @@ impl Calculator { /// Enter a string with an infix expression (example: "2 * (2 + 1)") as parameter. /// Returns a result containing the evaluated result of the expression, or an error + /// + /// ``` + /// let mut calculator = Calculator::new(); + /// let res = calculator.calculate_infix("1 + 6 / 3").unwrap(); + /// + /// assert_eq!(res, "3"); + /// ``` pub fn calculate_infix(&mut self, input: &str) -> Result { let mut eq_position = None; @@ -90,6 +98,14 @@ impl Calculator { /// Calculates a postfix expression and returns a single numerical value. (Or an error if the /// expression is malformed) + /// + /// ``` + /// let mut calculator = Calculator::new(); + /// let tokens = vec![Number(1.0), Number(1.0), Op(Plus)]; + /// let res = calculator.eval_postfix(tokens).unwrap(); + /// + /// assert_eq!(res, 2.0); + /// ``` fn eval_postfix(&self, input: Vec) -> Result { let mut stack = Vec::new(); for token in input { @@ -303,4 +319,40 @@ mod calculate_infix_tests { let res = calculator.calculate_infix("(1 + 2) * 3"); assert_eq!(res.unwrap(), "9"); } + + #[test] + fn error_when_extra_before_equals() { + let mut calculator = Calculator::new(); + let res = calculator.calculate_infix("a b = 1"); + + assert!(res.is_err()); + } + + #[test] + fn error_equals_without_variable() { + let mut calculator = Calculator::new(); + let res = calculator.calculate_infix("= 1 + 2"); + + assert!(res.is_err()); + } + + #[test] + fn correct_variables_stored_and_returned() { + let mut calculator = Calculator::new(); + let res = calculator.calculate_infix("a = 1 + 2"); + assert_eq!(res.unwrap(), "3"); + + let res = calculator.calculate_infix("b = 1 + a"); + assert_eq!(res.unwrap(), "4"); + + let res = calculator.calculate_infix("b + a + a"); + assert_eq!(res.unwrap(), "10"); + } + + #[test] + fn error_bad_variable_input() { + let mut calculator = Calculator::new(); + let res = calculator.calculate_infix("* = 1 + 2"); + assert!(res.is_err()); + } } diff --git a/src/logic/tokenize.rs b/src/logic/tokenize.rs index 6d70dbb..095d5ed 100644 --- a/src/logic/tokenize.rs +++ b/src/logic/tokenize.rs @@ -1,5 +1,4 @@ use super::enums::Token::{self, *}; -//use super::enums::Number; use super::enums::Operator::{self, *}; use super::enums::Function; @@ -86,10 +85,20 @@ pub fn tokenize(input: &str) -> Result, String> { var_string.push(c); let mut is_function = false; + let mut found_whitespace = false; while let Some(&c) = chars.peek() { if c.is_alphanumeric() { + + // 1 + a b + 2 is not valid syntax (`a b` is two variables after each other) + // have to check here (instead of just forbidding all whitespace) because a + // function can have spaces between the characters and the parentheses: + // sin (2) == sin(2) + if found_whitespace { + break; + } var_string.push(c); } else if c.is_whitespace() { + found_whitespace = true; } else if c == '(' { is_function = true; break; @@ -120,7 +129,14 @@ pub fn tokenize(input: &str) -> Result, String> { Ok(output) } -/// Return true if `c` is one of the defined mathematical operators +/// Return an `Operator` enum if `c` is one of the defined mathematical operators +/// ``` +/// let op = get_operator('+').unwrap(); +/// assert_eq!(op, Operator::Plus); +/// +/// let op = get_operator('a'); +/// assert_eq!(op, None); +/// ``` fn get_operator(c: char) -> Option { use self::Operator::*; match c { @@ -135,6 +151,15 @@ fn get_operator(c: char) -> Option { } } +/// Input is a `&str`, returns a Function enum: +/// +/// ``` +/// let fun = get_function("sin").unwrap(); +/// assert_eq!(fun, Function::Sin); +/// +/// let fun = get_function("The answer to life, the universe, and everything"); +/// assert_eq!(fun, None); +/// ``` fn get_function(s: &str) -> Option { use self::Function::*; match &*s.to_lowercase() {