1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use alloc::vec::Vec;
use calc_common::Character;
use calc_parser::Evaluator;

pub struct CalcEvaluator;

impl Evaluator for CalcEvaluator {
    type Item = i32;

    type Error = ();

    fn evaluate(expr: calc_parser::Expression<Self::Item>) -> Result<Self::Item, Self::Error> {
        if let Some(first_argument) = expr.first_argument {
            match expr.operator {
                calc_parser::Operator::Add => Ok(first_argument + expr.second_argument),
                calc_parser::Operator::Subtract => Ok(first_argument - expr.second_argument),
                calc_parser::Operator::Multiply => Ok(first_argument * expr.second_argument),
                calc_parser::Operator::Divide => Ok(first_argument / expr.second_argument),
                calc_parser::Operator::Exponentiate => {
                    Ok(first_argument.pow(expr.second_argument.unsigned_abs()))
                }
            }
        } else {
            match expr.operator {
                calc_parser::Operator::Subtract => Ok(expr.second_argument),
                _ => Err(()),
            }
        }
    }

    fn add_digit(mut number_so_far: Self::Item, next_digit: u8) -> Self::Item {
        number_so_far *= 10;
        number_so_far += i32::from(next_digit);

        number_so_far
    }

    fn zero() -> Self::Item {
        0
    }
}

pub fn number_to_chars(mut num: i32) -> Vec<Character> {
    // Maximum power of ten representable as a i32
    const MAX_DEC: u32 = 10u32.pow((i32::MAX as u32).ilog10());

    let mut div = MAX_DEC;
    let mut chars = Vec::new();
    let mut hit_nonzero_digit = false;

    if num < 0 {
        chars.push(Character::Minus);
        num = -num;
    }

    let mut num = num as u32;

    if num == 0 {
        chars.push(Character::Zero);
        return chars;
    }

    while div > 0 {
        let digit = num / div;

        num -= digit * div;

        if digit != 0 {
            hit_nonzero_digit = true;
        }

        if hit_nonzero_digit {
            let Some(digit) = Character::from_digit(digit as u8) else {
                unreachable!()
            };

            chars.push(digit);
        }

        div /= 10;
    }

    chars
}