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}