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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use core::{iter::Peekable, marker::PhantomData};

use calc_common::Character;

use crate::{Evaluator, Operator};

#[derive(Debug)]
pub enum Token<I> {
    Operator(Operator),
    Number(I),
    OpenParenthesis(),
    ClosingParenthesis(),
}

/// An iterator over the [`Token`]s in a stream of characters
pub struct Lexer<E, I>
where
    I: Iterator<Item = Character>,
    E: Evaluator,
{
    iter: Peekable<I>,
    phantomdata: PhantomData<E>,
}

impl<I: Iterator<Item = Character>, E: Evaluator> Lexer<E, I> {
    pub fn new(iter: I) -> Self {
        Self {
            iter: iter.peekable(),
            phantomdata: PhantomData,
        }
    }
}

impl<I: Iterator<Item = Character>, E: Evaluator> Iterator for Lexer<E, I> {
    type Item = Token<E::Item>;

    fn next(&mut self) -> Option<Token<E::Item>> {
        let mut num = E::zero();
        let mut num_created = false;

        loop {
            let next_char = self.iter.peek().copied();

            let token = match next_char {
                Some(Character::OpenParen) => Some(Token::OpenParenthesis()),
                Some(Character::CloseParen) => Some(Token::ClosingParenthesis()),
                Some(Character::Plus) => Some(Token::Operator(Operator::Add)),
                Some(Character::Minus) => Some(Token::Operator(Operator::Subtract)),
                Some(Character::Multiply) => Some(Token::Operator(Operator::Multiply)),
                Some(Character::Slash) => Some(Token::Operator(Operator::Divide)),
                Some(Character::Caret) => Some(Token::Operator(Operator::Exponentiate)),
                Some(Character::Dot) => unimplemented!(),
                Some(
                    // All digits are explicitly laid out so that if new Characters are added, this match statement doesn't compile
                    digit @ (Character::Zero
                    | Character::One
                    | Character::Two
                    | Character::Three
                    | Character::Four
                    | Character::Five
                    | Character::Six
                    | Character::Seven
                    | Character::Eight
                    | Character::Nine),
                ) => {
                    let num_delta = digit as u8;

                    num = E::add_digit(num, num_delta);

                    num_created = true;
                    self.iter.next();
                    continue;
                }
                Some(
                    character @ (Character::A
                    | Character::B
                    | Character::C
                    | Character::D
                    | Character::E
                    | Character::F
                    | Character::G
                    | Character::H
                    | Character::I
                    | Character::J
                    | Character::K
                    | Character::L
                    | Character::M
                    | Character::N
                    | Character::O
                    | Character::P
                    | Character::Q
                    | Character::R
                    | Character::S
                    | Character::T
                    | Character::U
                    | Character::V
                    | Character::W
                    | Character::X
                    | Character::Y
                    | Character::Z),
                ) => {
                    let _ = character;
                    todo!()
                }
                None => None,
            };

            if !num_created {
                self.iter.next();
                return token;
            }

            return Some(Token::Number(num));
        }
    }
}