1mod cursor;
3mod token;
4mod unicode;
5
6pub use cursor::Cursor;
7pub use token::Token;
8
9pub struct Lexer<'a> {
10 source: &'a str,
11 pos: usize,
12}
13
14impl<'a> Lexer<'a> {
15 pub fn new(source: &'a str) -> Self {
16 Self { source, pos: 0 }
17 }
18
19 fn peek(&self) -> Option<char> {
20 self.source[self.pos..].chars().next()
21 }
22
23 fn peek_nth(&self, n: usize) -> Option<char> {
24 self.source[self.pos..].chars().nth(n)
25 }
26
27 fn advance(&mut self) -> Option<char> {
28 let ch = self.source[self.pos..].chars().next()?;
29 self.pos += ch.len_utf8();
30 Some(ch)
31 }
32
33 fn rest(&self) -> &str {
34 &self.source[self.pos..]
35 }
36
37 fn skip_whitespace_and_comments(&mut self) {
38 loop {
39 while matches!(
40 self.peek(),
41 Some(' ') | Some('\t') | Some('\n') | Some('\r') | Some('\x0C')
42 ) {
43 self.advance();
44 }
45 if self.peek() == Some('/') && self.peek_nth(1) == Some('/') {
46 while self.peek().is_some_and(|c| c != '\n') {
47 self.advance();
48 }
49 continue;
50 }
51 if self.peek() == Some('#') {
53 while self.peek().is_some_and(|c| c != '\n') {
54 self.advance();
55 }
56 continue;
57 }
58 break;
59 }
60 }
61
62 fn lex_string(&mut self) -> Token {
63 self.advance(); let mut s = std::string::String::new();
65 loop {
66 match self.advance() {
67 None => break,
68 Some('"') => break,
69 Some('\\') => match self.advance() {
70 Some('n') => s.push('\n'),
71 Some('t') => s.push('\t'),
72 Some('r') => s.push('\r'),
73 Some('"') => s.push('"'),
74 Some('\\') => s.push('\\'),
75 Some('0') => s.push('\0'),
76 Some(c) => {
77 s.push('\\');
78 s.push(c);
79 },
80 None => break,
81 },
82 Some(c) => s.push(c),
83 }
84 }
85 Token::String(s)
86 }
87
88 fn lex_number(&mut self) -> Token {
89 let start = self.pos;
90 let mut has_dot = false;
91 loop {
92 match self.peek() {
93 Some('0'..='9') => {
94 self.advance();
95 },
96 Some('.') if !has_dot && matches!(self.peek_nth(1), Some('0'..='9')) => {
97 has_dot = true;
98 self.advance();
99 },
100 _ => break,
101 }
102 }
103 Token::Number(self.source[start..self.pos].to_string())
104 }
105
106 fn lex_word(&mut self) -> Token {
107 let start = self.pos;
108 while let Some(c) = self.peek() {
112 if c.is_alphanumeric() || c == '_' || is_unicode_combining(c) {
113 self.advance();
114 } else {
115 break;
116 }
117 }
118 let word = &self.source[start..self.pos];
119 Self::classify_word(word)
120 }
121
122 fn classify_word(word: &str) -> Token {
126 match word {
127 "bind" | "令" | "灵符" => Token::Bind,
129 "do" | "执" => Token::Do,
130 "fn" | "函" => Token::Fn,
131 "mod" | "核" => Token::Mod,
132 "type" | "符" | "型" | "타입" | "ชนิด" => Token::Type,
133 "use" | "载" | "引" | "사용" | "使う" | "ใช้" | "นำเข้า" | "importar" | "nutzen"
135 | "utiliser" => Token::Use,
136 "if" | "若" | "如" => Token::If,
137 "else" | "否则" | "否" => Token::Else,
138 "while" | "循" | "当" => Token::While,
139 "for" | "历" => Token::For,
140 "in" | "于" => Token::In,
141 "match" | "配" => Token::Match,
142 "return" | "归" => Token::Return,
143 "own" | "拥有" | "独" | "所有" | "소유" | "เป็นเจ้าของ" => Token::Own,
144 "lend" | "借" | "貸す" | "빌려" | "ให้ยืม" => Token::Lend,
145 "share" | "共享" | "共" | "共有" | "공유" | "แบ่งปัน" => Token::Share,
146 "move" | "移动" | "移" | "移動" | "이동" | "ย้าย" => Token::Move,
147 "copy" | "复制" | "复" | "複製" | "복사" | "คัดลอก" => Token::Copy,
148 "async" | "异步" | "异" => Token::Async,
149 "wait" | "等待" | "待" => Token::Wait,
150 "as" | "为" | "として" | "로서" | "เป็น" => Token::As,
151 "where" | "条件" | "但し" | "단" | "โดยที่" => Token::Where,
152 "post" | "发布" | "出" | "投稿" | "게시" | "ส่ง" => Token::Post,
153 "give" | "给" | "予" | "渡す" | "전달" | "ให้" => Token::Give,
154 "fit" | "适合" | "適合" | "적합" | "เหมาะสม" => Token::Fit,
155 "form" | "形式" | "形" | "構造" | "구조" | "โครงสร้าง" => {
157 Token::Form
158 },
159 "choose" | "选择" | "选" | "選択" | "선택" | "เลือกแบบ" => {
161 Token::Choose
162 },
163 "can" | "能" | "できる" | "가능" | "สามารถ" => Token::Can,
164 "change" | "改变" | "变" | "変える" | "변경" | "เปลี่ยนแปลง" => Token::Change,
165 "stop" | "停止" | "止" | "หยุด" => Token::Stop,
168 "again" | "继续" | "ทำอีก" => Token::Again,
169 "try" | "尝试" | "试" | "ลอง" => Token::Try,
170 "sure" | "确定" | "确" | "確か" | "확실" | "แน่นอน" => Token::Sure,
171 "maybe" | "可能" | "或" | "多分" | "아마도" | "อาจจะ" => Token::Maybe,
172 "pure" | "纯" | "純粋" | "순수" | "บริสุทธิ์" => Token::Pure,
173 "spawn" | "生成" | "启" | "สร้าง" => Token::Spawn,
174 "asm" => Token::Asm,
175 "ok" | "好" | "可" | "良い" | "좋아" | "ตกลง" => Token::Ok,
176 "bad" | "坏" | "误" | "悪い" | "나쁨" | "ผิดพลาด" => Token::Bad,
177 "none" | "无" | "なし" | "없음" | "ไม่มี" => Token::None,
178 "束縛" | "バ" => Token::Bind,
180 "実行" | "執" => Token::Do,
181 "関数" | "関" => Token::Fn,
182 "モジュール" | "模" => Token::Mod,
183 "もし" => Token::If,
184 "他" => Token::Else,
185 "間" | "一方" => Token::While,
186 "繰" | "ために" => Token::For,
187 "の中" => Token::In,
188 "一致" => Token::Match,
189 "戻る" | "帰る" => Token::Return,
190 "試す" => Token::Try,
191 "待つ" => Token::Wait,
192 "非同期" => Token::Async,
193 "起動" => Token::Spawn,
194 "止まれ" | "停め" => Token::Stop,
195 "継続" => Token::Again,
196 "true" | "真" => Token::Bool(true),
198 "false" | "假" | "偽" => Token::Bool(false),
199 "바인드" | "묶" => Token::Bind,
201 "실행" => Token::Do,
202 "함수" => Token::Fn,
203 "모듈" => Token::Mod,
204 "만약" | "조건" => Token::If,
205 "아니면" => Token::Else,
206 "동안" | "반복" => Token::While,
207 "위해" => Token::For,
208 "안에" => Token::In,
209 "매치" => Token::Match,
210 "반환" | "귀환" => Token::Return,
211 "시도" => Token::Try,
212 "기다려" => Token::Wait,
213 "비동기" => Token::Async,
214 "생성" => Token::Spawn,
215 "멈춤" => Token::Stop,
216 "계속" => Token::Again,
217 "참" => Token::Bool(true),
218 "거짓" => Token::Bool(false),
219 "связать" => Token::Bind,
221 "сделать" => Token::Do,
222 "если" => Token::If,
223 "иначе" => Token::Else,
224 "пока" => Token::While,
225 "для" => Token::For,
226 "вернуть" => Token::Return,
227 "ผูก" => Token::Bind,
229 "ทำ" => Token::Do,
230 "ฟังก์ชัน" => Token::Fn,
231 "โมดูล" => Token::Mod,
232 "ถ้า" => Token::If,
233 "มิฉะนั้น" => Token::Else,
234 "ขณะที่" => Token::While,
235 "สำหรับ" => Token::For,
236 "ใน" => Token::In,
237 "จับคู่" => Token::Match,
238 "คืน" => Token::Return,
239 "รอ" => Token::Wait,
240 "ไม่พร้อมกัน" => Token::Async,
241 "จริง" => Token::Bool(true),
242 "เท็จ" => Token::Bool(false),
243 "बाँधो" => Token::Bind,
245 "करो" => Token::Do,
246 "अगर" => Token::If,
247 "नहींतो" => Token::Else,
248 "जबकि" => Token::While,
249 "केलिए" => Token::For,
250 "वापस" => Token::Return,
251 "सत्य" => Token::Bool(true),
252 "असत्य" => Token::Bool(false),
253 "ربط" => Token::Bind,
255 "افعل" => Token::Do,
256 "إذا" => Token::If,
257 "وإلا" => Token::Else,
258 "بينما" => Token::While,
259 "لأجل" => Token::For,
260 "في" => Token::In,
261 "أعد" => Token::Return,
262 "صحيح" => Token::Bool(true),
263 "خطأ" => Token::Bool(false),
264 "enlazar" => Token::Bind,
266 "hacer" => Token::Do,
267 "si" => Token::If,
268 "sino" => Token::Else,
269 "mientras" => Token::While,
270 "para" => Token::For,
271 "retornar" => Token::Return,
272 "verdadero" => Token::Bool(true),
273 "falso" => Token::Bool(false),
274 "lier" => Token::Bind,
276 "faire" => Token::Do,
277 "func" => Token::Fn,
278 "module" => Token::Mod,
279 "sinon" => Token::Else,
280 "tantque" => Token::While,
281 "retourner" => Token::Return,
282 "vrai" => Token::Bool(true),
283 "faux" => Token::Bool(false),
284 "binden" => Token::Bind,
286 "machen" => Token::Do,
287 "wenn" => Token::If,
288 "sonst" => Token::Else,
289 "solange" => Token::While,
290 "für" => Token::For,
291 "zurück" => Token::Return,
292 "wahr" => Token::Bool(true),
293 "falsch" => Token::Bool(false),
294 "ligar" => Token::Bind,
296 "fazer" => Token::Do,
297 "se" => Token::If,
298 "senão" => Token::Else,
299 "enquanto" => Token::While,
300 "verdadeiro" => Token::Bool(true),
301 other => Token::Ident(other.to_string()),
303 }
304 }
305
306 pub fn next_token(&mut self) -> Option<Token> {
307 self.skip_whitespace_and_comments();
308 let ch = self.peek()?;
309
310 if ch == '"' {
312 return Some(self.lex_string());
313 }
314
315 if ch.is_ascii_digit() {
317 return Some(self.lex_number());
318 }
319
320 if ch.is_alphabetic() || ch == '_' || is_unicode_combining(ch) {
322 return Some(self.lex_word());
323 }
324
325 let rest = self.rest();
327
328 if rest.starts_with("..") {
330 self.advance();
331 self.advance();
332 return Some(Token::DotDot);
333 }
334 if rest.starts_with("::") {
336 self.advance();
337 self.advance();
338 return Some(Token::ColonColon);
339 }
340 if rest.starts_with("==") {
342 self.advance();
343 self.advance();
344 return Some(Token::EqEq);
345 }
346 if rest.starts_with("!=") {
348 self.advance();
349 self.advance();
350 return Some(Token::Ne);
351 }
352 if rest.starts_with("<=") {
354 self.advance();
355 self.advance();
356 return Some(Token::Le);
357 }
358 if rest.starts_with(">=") {
360 self.advance();
361 self.advance();
362 return Some(Token::Ge);
363 }
364 if rest.starts_with("->") {
366 self.advance();
367 self.advance();
368 return Some(Token::Arrow);
369 }
370 if rest.starts_with("=>") {
372 self.advance();
373 self.advance();
374 return Some(Token::FatArrow);
375 }
376 if rest.starts_with("&&") {
378 self.advance();
379 self.advance();
380 return Some(Token::And);
381 }
382 if rest.starts_with("||") {
384 self.advance();
385 self.advance();
386 return Some(Token::Or);
387 }
388
389 self.advance();
391 Some(match ch {
392 '=' => Token::Eq,
393 '<' => Token::Lt,
394 '>' => Token::Gt,
395 '!' => Token::Not,
396 '+' => Token::Plus,
397 '-' => Token::Minus,
398 '*' => Token::Star,
399 '/' => Token::Slash,
400 '%' => Token::Percent,
401 '.' => Token::Dot,
402 '&' => Token::Ampersand,
403 '(' => Token::LParen,
404 ')' => Token::RParen,
405 '{' => Token::LBrace,
406 '}' => Token::RBrace,
407 '[' => Token::LBracket,
408 ']' => Token::RBracket,
409 ',' => Token::Comma,
410 ':' => Token::Colon,
411 ';' => Token::Semicolon,
412 '|' => Token::Or, c => Token::Error(c.to_string()),
414 })
415 }
416}
417
418fn is_unicode_combining(c: char) -> bool {
422 let cp = c as u32;
423 matches!(cp,
424 0x0300..=0x036F | 0x0483..=0x0489 | 0x0591..=0x05C7 | 0x0610..=0x061A | 0x064B..=0x065F | 0x0670 | 0x06D6..=0x06DC | 0x0730..=0x074A | 0x0816..=0x082D | 0x0900..=0x0903 | 0x093A..=0x094F | 0x0951..=0x0957 | 0x0962..=0x0963 | 0x0981..=0x0983 | 0x09BC | 0x09BE..=0x09C4 | 0x09C7..=0x09C8 | 0x09CB..=0x09CD | 0x0A01..=0x0A03 | 0x0A3C | 0x0A3E..=0x0A42 | 0x0B01..=0x0B03 | 0x0B3C..=0x0B4D | 0x0C00..=0x0C03 | 0x0C3E..=0x0C56 | 0x0D00..=0x0D03 | 0x0D3B..=0x0D4D | 0x0E31 | 0x0E34..=0x0E3A | 0x0E47..=0x0E4E | 0x0EB1 | 0x0EB4..=0x0EBC | 0x0EC8..=0x0ECD | 0x3099..=0x309A | 0xFE20..=0xFE2F )
460}