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
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Operator {
Plus,
Minus,
Star,
Slash,
Percent,
Caret,
LParen,
RParen,
}
use self::Operator::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Function {
Sqrt,
Sin,
Cos,
Tan,
Log,
}
use self::Function::*;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Token {
Number(f64),
Operator(Operator),
Function(Function),
}
#[derive(Debug, Clone, PartialEq)]
pub enum LexerError {
InvalidCharacter(char),
InvalidNumber(String),
InvalidIdentifier(String),
}
pub fn tokenize(input: &str) -> Result<Vec<Token>, LexerError> {
let mut tokens = Vec::<Token>::new();
let chars: Vec<char> = input.chars().collect();
let mut i = 0usize;
while i < chars.len() {
match chars[i] {
'+' => tokens.push(Token::Operator(Plus)),
'-' => tokens.push(Token::Operator(Minus)),
'*' | '•' | '×' => tokens.push(Token::Operator(Star)),
'/' | '÷' => tokens.push(Token::Operator(Slash)),
'%' => tokens.push(Token::Operator(Percent)),
'^' => tokens.push(Token::Operator(Caret)),
'(' => tokens.push(Token::Operator(LParen)),
')' => tokens.push(Token::Operator(RParen)),
'√' => tokens.push(Token::Function(Sqrt)),
c => {
if c.is_whitespace() {
i += 1;
continue;
} else if c.is_digit(10) || c == '.' {
let mut number_string = c.to_string();
i += 1;
while i < chars.len() && (chars[i].is_digit(10) || chars[i] == '.') {
number_string.push(chars[i]);
i += 1;
}
match number_string.parse::<f64>() {
Ok(num) => tokens.push(Token::Number(num)),
_ => return Err(LexerError::InvalidNumber(number_string)),
}
continue;
} else if c.is_alphabetic() {
let mut full_identifier = c.to_string();
i += 1;
while i < chars.len() && chars[i].is_alphabetic() {
full_identifier.push(chars[i]);
i += 1;
}
match &full_identifier.to_lowercase()[..] {
"sqrt" => tokens.push(Token::Function(Sqrt)),
"sin" => tokens.push(Token::Function(Sin)),
"cos" => tokens.push(Token::Function(Cos)),
"tan" => tokens.push(Token::Function(Tan)),
"log" => tokens.push(Token::Function(Log)),
_ => return Err(LexerError::InvalidIdentifier(full_identifier)),
}
continue;
} else {
return Err(LexerError::InvalidCharacter(c));
}
}
}
i += 1;
}
Ok(tokens)
}