mex/scanner/
mod.rs

1pub mod token;
2
3pub struct Scanner {
4    chars: Vec<char>,
5    next_index: usize,
6}
7
8impl Scanner {
9    #[allow(dead_code)]
10    pub fn new(s: String) -> Scanner {
11        let chars = s.chars().collect::<Vec<char>>();
12        let next_index = 0;
13
14        Scanner{chars, next_index}
15    }
16
17    fn advance(&mut self) -> Option<char> {
18        if self.next_index == 0 || self.next_index >= self.chars.len() + 1 {
19            self.next_index += 1;
20            return None
21        }
22    
23        let ch = self.chars[self.next_index - 1];
24        self.next_index += 1;
25
26        Some(ch)
27    }
28
29    fn peek(&mut self) -> Option<char> {
30        if self.next_index >= self.chars.len() {
31            return None
32        }
33
34        Some(self.chars[self.next_index])
35    }
36
37    fn take_while<T>(&mut self, mut pred: T) -> String
38        where T: FnMut(char) -> bool
39    {
40        let mut out: String = String::new();
41
42        loop {
43            if let Some(next) = self.peek() {
44                if !pred(next) {
45                    break
46                }
47
48                out.push(next);
49
50                self.next_index += 1;
51            } else {
52                break
53            }
54        }
55
56        out
57    }
58}
59
60impl Iterator for Scanner {
61    type Item = token::Token;
62
63    fn next(&mut self) -> Option<Self::Item> {
64        let (literal, t, adv) = match self.peek() {
65            Some('+') => ("+".to_string(), token::Type::Plus, true),
66            Some('-') => ("-".to_string(), token::Type::Minus, true),
67            Some('*') => ("*".to_string(), token::Type::Multiply, true),
68            Some('/') => ("/".to_string(), token::Type::Divide, true),
69            Some('(') => ("(".to_string(), token::Type::LeftParen, true),
70            Some(')') => (")".to_string(), token::Type::RightParen, true),
71            Some('=') => ("=".to_string(), token::Type::Equals, true),
72
73            Some(c) if c.is_whitespace() => {
74                self.take_while(|x| x.is_whitespace());
75                return self.next();
76            }
77
78            Some(c) if c.is_digit(10) => {
79                let mut has_dot = false;
80
81                let literal = self.take_while(|x| {
82                    if x == '.' && !has_dot {
83                        has_dot = true;
84                        true
85                    } else {
86                        x.is_digit(10)
87                    }
88                });
89
90                (literal, token::Type::Number, false)
91            }
92
93            Some(c) if c.is_alphabetic() => {
94                let literal = self.take_while(|x| x.is_alphanumeric());
95                (literal, token::Type::Identifier, false)
96            }
97
98            Some(c) => (c.to_string(), token::Type::Illegal, true),
99            None => return None,
100        };
101
102        if adv {
103            self.advance();
104        }
105
106        Some(token::Token{literal, t})
107    }
108}