1use std::result::Result;
2use super::token::TokenType;
3
4
5#[derive(Debug, Clone)]
6pub struct Token {
7 pub token_type: TokenType,
8 pub line: usize,
9 pub column: usize,
10 pub lexeme: String,
11}
12
13pub fn tokenize(source: &str) -> Result<Vec<Token>, String> {
14 let mut tokens = Vec::new();
15 let chars: Vec<char> = source.chars().collect();
16 let mut i = 0;
17 let mut line = 1;
18 let mut col = 1;
19
20 while i < chars.len() {
21 let ch = chars[i];
22 let start_col = col;
23 match ch {
24 ' ' | '\t' | '\r' => {
25 i += 1;
26 col += 1;
27 }
28 '\n' => {
29 i += 1;
30 line += 1;
31 col = 1;
32 }
33 '/' => {
34 if i + 1 < chars.len() && chars[i + 1] == '/' {
35 i += 2;
37 while i < chars.len() && chars[i] != '\n' {
38 i += 1;
39 col += 1;
40 }
41 continue;
42 }
43 tokens.push(Token {
44 token_type: TokenType::Slash,
45 line,
46 column: start_col,
47 lexeme: "/".to_string(),
48 });
49 i += 1;
50 col += 1;
51 }
52 '"' => {
53 i += 1;
54 col += 1;
55 let mut s = String::new();
56 while i < chars.len() && chars[i] != '"' {
57 s.push(chars[i]);
58 i += 1;
59 col += 1;
60 }
61 if i < chars.len() {
62 i += 1;
63 col += 1;
64 }
65 let s_clone = s.clone();
66 tokens.push(Token {
67 token_type: TokenType::String(s),
68 line,
69 column: start_col,
70 lexeme: format!("\"{}\"", s_clone),
71 });
72
73 }
74 '0'..='9' => {
75 let mut num = String::new();
76 while i < chars.len() && chars[i].is_ascii_digit() {
77 num.push(chars[i]);
78 i += 1;
79 col += 1;
80 }
81 let n: f64 = num.parse().map_err(|_| "Invalid number".to_string())?;
82 tokens.push(Token {
83 token_type: TokenType::Number(n),
84 line,
85 column: start_col,
86 lexeme: num,
87 });
88 }
89 'a'..='z' | 'A'..='Z' | '_' => {
90 let mut ident = String::new();
91 while i < chars.len() && (chars[i].is_alphanumeric() || chars[i] == '_') {
92 ident.push(chars[i]);
93 i += 1;
94 col += 1;
95 }
96 let ttype = match ident.as_str() {
97 "let" => TokenType::Let,
98 "const" => TokenType::Const,
99 "fn" => TokenType::Fn,
100 "if" => TokenType::If,
101 "else" => TokenType::Else,
102 "elif" => TokenType::Elif,
103 "while" => TokenType::While,
104 "for" => TokenType::For,
105"in" => TokenType::In,
106 "return" => TokenType::Return,
107"true" => TokenType::True,
108"false" => TokenType::False,
109 "null" => TokenType::Null,
110 "break" => TokenType::Break,
111 "continue" => TokenType::Continue,
112 "system" => TokenType::System,
113 "import" => TokenType::Import,
114_ => TokenType::Identifier(ident.clone()),
115 };
116 tokens.push(Token {
117 token_type: ttype,
118 line,
119 column: start_col,
120 lexeme: ident,
121 });
122 }
123 '!' => {
124 i += 1;
125 col += 1;
126 tokens.push(Token {
127 token_type: TokenType::Bang,
128 line,
129 column: start_col,
130 lexeme: "!".to_string(),
131 });
132 }
133 '+' => {
134 tokens.push(Token { token_type: TokenType::Plus, line, column: start_col, lexeme: "+".to_string() });
135 i += 1;
136 col += 1;
137 }
138 '-' => {
139 tokens.push(Token { token_type: TokenType::Minus, line, column: start_col, lexeme: "-".to_string() });
140 i += 1;
141 col += 1;
142 }
143 '*' => {
144 tokens.push(Token { token_type: TokenType::Star, line, column: start_col, lexeme: "*".to_string() });
145 i += 1;
146 col += 1;
147 }
148 '=' => {
149 if i + 1 < chars.len() && chars[i + 1] == '=' {
150 i += 2;
151 col += 2;
152 tokens.push(Token { token_type: TokenType::EqualEqual, line, column: start_col, lexeme: "==".to_string() });
153 } else {
154 i += 1;
155 col += 1;
156 tokens.push(Token { token_type: TokenType::Assign, line, column: start_col, lexeme: "=".to_string() });
157 }
158 }
159 '<' => {
160 if i + 1 < chars.len() && chars[i + 1] == '=' {
161 i += 2;
162 col += 2;
163 tokens.push(Token { token_type: TokenType::Lte, line, column: start_col, lexeme: "<=".to_string() });
164 } else {
165 i += 1;
166 col += 1;
167 tokens.push(Token { token_type: TokenType::Lt, line, column: start_col, lexeme: "<".to_string() });
168 }
169 }
170 '>' => {
171 if i + 1 < chars.len() && chars[i + 1] == '=' {
172 i += 2;
173 col += 2;
174 tokens.push(Token { token_type: TokenType::Gte, line, column: start_col, lexeme: ">=".to_string() });
175 } else {
176 i += 1;
177 col += 1;
178 tokens.push(Token { token_type: TokenType::Gt, line, column: start_col, lexeme: ">".to_string() });
179 }
180 }
181 '(' => {
182 tokens.push(Token { token_type: TokenType::LeftParen, line, column: start_col, lexeme: "(".to_string() });
183 i += 1;
184 col += 1;
185 }
186 ')' => {
187 tokens.push(Token { token_type: TokenType::RightParen, line, column: start_col, lexeme: ")".to_string() });
188 i += 1;
189 col += 1;
190 }
191 '{' => {
192 tokens.push(Token { token_type: TokenType::LeftBrace, line, column: start_col, lexeme: "{".to_string() });
193 i += 1;
194 col += 1;
195 }
196 '}' => {
197 tokens.push(Token { token_type: TokenType::RightBrace, line, column: start_col, lexeme: "}".to_string() });
198 i += 1;
199 col += 1;
200 }
201 ';' => {
202 tokens.push(Token { token_type: TokenType::Semicolon, line, column: start_col, lexeme: ";".to_string() });
203 i += 1;
204 col += 1;
205 }
206 ',' => {
207 tokens.push(Token { token_type: TokenType::Comma, line, column: start_col, lexeme: ",".to_string() });
208 i += 1;
209 col += 1;
210 }
211 '[' => {
212 tokens.push(Token { token_type: TokenType::LBracket, line, column: start_col, lexeme: "[".to_string() });
213 i += 1;
214 col += 1;
215 }
216 ']' => {
217 tokens.push(Token { token_type: TokenType::RBracket, line, column: start_col, lexeme: "]".to_string() });
218 i += 1;
219 col += 1;
220 }
221 ':' => {
222 if i + 1 < chars.len() && chars[i + 1] == ':' {
223 tokens.push(Token { token_type: TokenType::Scope, line, column: start_col, lexeme: "::".to_string() });
224 i += 2;
225 col += 2;
226 } else {
227 tokens.push(Token { token_type: TokenType::Colon, line, column: start_col, lexeme: ":".to_string() });
228 i += 1;
229 col += 1;
230 }
231 }
232 '%' => {
233 tokens.push(Token { token_type: TokenType::Percent, line, column: start_col, lexeme: "%".to_string() });
234 i += 1;
235 col += 1;
236 }
237 _ => {
238 i += 1;
239 col += 1;
240 }
241 }
242 }
243
244 tokens.push(Token {
245 token_type: TokenType::Eof,
246 line,
247 column: col,
248 lexeme: "".to_string(),
249 });
250
251 Ok(tokens)
252}
253