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
use std::char;
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
Number(f64),
Times,
Div,
Frac,
Plus,
Minus,
LParen,
RParen,
LBrace,
RBrace,
}
pub struct Lexer {
input: Vec<char>,
position: usize,
}
impl Lexer {
pub fn init(input: Vec<char>) -> Lexer {
Lexer { input, position: 0 }
}
pub fn token(&mut self) -> Result<Option<Token>, String> {
while self.curr().is_some() && self.curr().unwrap().is_whitespace() {
self.next();
}
let token = if self.curr().is_some() && Self::is_number(self.curr().unwrap()) {
let mut number = vec![*self.curr().unwrap()];
while self.peek().is_some() && Self::is_number(self.peek().unwrap()) {
self.next();
number.push(*self.curr().unwrap());
}
Ok(String::from_iter(number)
.parse::<f64>()
.ok()
.map(Token::Number))
} else if self.curr() == Some(&'\\') {
let mut command = vec![*self.curr().unwrap()];
while self.peek().is_some() && self.peek().unwrap().is_ascii_alphabetic() {
self.next();
command.push(*self.curr().unwrap());
}
match String::from_iter(command).as_str() {
"\\times" => Ok(Some(Token::Times)),
"\\div" => Ok(Some(Token::Div)),
"\\frac" => Ok(Some(Token::Frac)),
_ => Err(String::from("unknown command")),
}
} else {
match self.curr() {
Some('+') => Ok(Some(Token::Plus)),
Some('-') => Ok(Some(Token::Minus)),
Some('(') => Ok(Some(Token::LParen)),
Some(')') => Ok(Some(Token::RParen)),
Some('{') => Ok(Some(Token::LBrace)),
Some('}') => Ok(Some(Token::RBrace)),
None => Ok(None),
_ => Err(String::from("unknown character")),
}
};
self.next();
token
}
fn next(&mut self) {
self.position += 1
}
fn curr(&mut self) -> Option<&char> {
self.input.get(self.position)
}
fn peek(&mut self) -> Option<&char> {
self.input.get(self.position + 1)
}
fn is_number(c: &char) -> bool {
c.is_ascii_digit() || c == &'.'
}
}