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" | "拥有" | "独" | "所有" | "소유" | "เป็นเจ้าของ" => {
144 Token::Own
145 },
146 "lend" | "借" | "貸す" | "빌려" | "ให้ยืม" => Token::Lend,
147 "share" | "共享" | "共" | "共有" | "공유" | "แบ่งปัน" => {
148 Token::Share
149 },
150 "move" | "移动" | "移" | "移動" | "이동" | "ย้าย" => Token::Move,
151 "copy" | "复制" | "复" | "複製" | "복사" | "คัดลอก" => Token::Copy,
152 "async" | "异步" | "异" => Token::Async,
153 "wait" | "等待" | "待" => Token::Wait,
154 "as" | "为" | "として" | "로서" | "เป็น" => Token::As,
155 "where" | "条件" | "但し" | "단" | "โดยที่" => Token::Where,
156 "post" | "发布" | "出" | "投稿" | "게시" | "ส่ง" => Token::Post,
157 "give" | "给" | "予" | "渡す" | "전달" | "ให้" => Token::Give,
158 "fit" | "适合" | "適合" | "적합" | "เหมาะสม" => Token::Fit,
159 "form" | "形式" | "形" | "構造" | "구조" | "โครงสร้าง" => {
161 Token::Form
162 },
163 "choose" | "选择" | "选" | "選択" | "선택" | "เลือกแบบ" => {
165 Token::Choose
166 },
167 "can" | "能" | "できる" | "가능" | "สามารถ" => Token::Can,
168 "change" | "改变" | "变" | "変える" | "변경" | "เปลี่ยนแปลง" => {
169 Token::Change
170 },
171 "stop" | "停止" | "止" | "หยุด" => Token::Stop,
174 "again" | "继续" | "ทำอีก" => Token::Again,
175 "try" | "尝试" | "试" | "ลอง" => Token::Try,
176 "sure" | "确定" | "确" | "確か" | "확실" | "แน่นอน" => Token::Sure,
177 "maybe" | "可能" | "或" | "多分" | "아마도" | "อาจจะ" => Token::Maybe,
178 "pure" | "纯" | "純粋" | "순수" | "บริสุทธิ์" => Token::Pure,
179 "spawn" | "生成" | "启" | "สร้าง" => Token::Spawn,
180 "asm" => Token::Asm,
181 "ok" | "好" | "可" | "良い" | "좋아" | "ตกลง" => Token::Ok,
182 "bad" | "坏" | "误" | "悪い" | "나쁨" | "ผิดพลาด" => Token::Bad,
183 "none" | "无" | "なし" | "없음" | "ไม่มี" => Token::None,
184 "束縛" | "バ" => Token::Bind,
186 "実行" | "執" => Token::Do,
187 "関数" | "関" => Token::Fn,
188 "モジュール" | "模" => Token::Mod,
189 "もし" => Token::If,
190 "他" => Token::Else,
191 "間" | "一方" => Token::While,
192 "繰" | "ために" => Token::For,
193 "の中" => Token::In,
194 "一致" => Token::Match,
195 "戻る" | "帰る" => Token::Return,
196 "試す" => Token::Try,
197 "待つ" => Token::Wait,
198 "非同期" => Token::Async,
199 "起動" => Token::Spawn,
200 "止まれ" | "停め" => Token::Stop,
201 "継続" => Token::Again,
202 "true" | "真" => Token::Bool(true),
204 "false" | "假" | "偽" => Token::Bool(false),
205 "바인드" | "묶" => Token::Bind,
207 "실행" => Token::Do,
208 "함수" => Token::Fn,
209 "모듈" => Token::Mod,
210 "만약" | "조건" => Token::If,
211 "아니면" => Token::Else,
212 "동안" | "반복" => Token::While,
213 "위해" => Token::For,
214 "안에" => Token::In,
215 "매치" => Token::Match,
216 "반환" | "귀환" => Token::Return,
217 "시도" => Token::Try,
218 "기다려" => Token::Wait,
219 "비동기" => Token::Async,
220 "생성" => Token::Spawn,
221 "멈춤" => Token::Stop,
222 "계속" => Token::Again,
223 "참" => Token::Bool(true),
224 "거짓" => Token::Bool(false),
225 "связать" => Token::Bind,
227 "сделать" => Token::Do,
228 "функция" => Token::Fn,
229 "модуль" => Token::Mod,
230 "тип" => Token::Type,
231 "использовать" => Token::Use,
232 "если" => Token::If,
233 "иначе" => Token::Else,
234 "пока" => Token::While,
235 "для" => Token::For,
236 "в" => Token::In,
237 "сопоставить" => Token::Match,
238 "вернуть" => Token::Return,
239 "владеть" => Token::Own,
240 "одолжить" => Token::Lend,
241 "делиться" => Token::Share,
242 "переместить" => Token::Move,
243 "копировать" => Token::Copy,
244 "асинхронно" => Token::Async,
245 "ждать" => Token::Wait,
246 "как" => Token::As,
247 "где" => Token::Where,
248 "опубликовать" => Token::Post,
249 "дать" => Token::Give,
250 "подходит" => Token::Fit,
251 "форма" => Token::Form,
252 "выбрать" => Token::Choose,
253 "может" => Token::Can,
254 "изменить" => Token::Change,
255 "стоп" => Token::Stop,
256 "снова" => Token::Again,
257 "пробовать" => Token::Try,
258 "уверен" => Token::Sure,
259 "возможно" => Token::Maybe,
260 "чистый" => Token::Pure,
261 "создать" => Token::Spawn,
262 "хорошо" => Token::Ok,
263 "плохо" => Token::Bad,
264 "ничего" => Token::None,
265 "истина" => Token::Bool(true),
266 "ложь" => Token::Bool(false),
267 "ผูก" => Token::Bind,
269 "ทำ" => Token::Do,
270 "ฟังก์ชัน" => Token::Fn,
271 "โมดูล" => Token::Mod,
272 "ถ้า" => Token::If,
273 "มิฉะนั้น" => Token::Else,
274 "ขณะที่" => Token::While,
275 "สำหรับ" => Token::For,
276 "ใน" => Token::In,
277 "จับคู่" => Token::Match,
278 "คืน" => Token::Return,
279 "รอ" => Token::Wait,
280 "ไม่พร้อมกัน" => Token::Async,
281 "จริง" => Token::Bool(true),
282 "เท็จ" => Token::Bool(false),
283 "बाँधो" => Token::Bind,
285 "करो" => Token::Do,
286 "अगर" => Token::If,
287 "नहींतो" => Token::Else,
288 "जबकि" => Token::While,
289 "केलिए" => Token::For,
290 "वापस" => Token::Return,
291 "सत्य" => Token::Bool(true),
292 "असत्य" => Token::Bool(false),
293 "ربط" => Token::Bind,
295 "افعل" => Token::Do,
296 "دالة" => Token::Fn,
297 "وحدة" => Token::Mod,
298 "نوع" => Token::Type,
299 "استخدم" => Token::Use,
300 "إذا" => Token::If,
301 "وإلا" => Token::Else,
302 "بينما" => Token::While,
303 "لأجل" => Token::For,
304 "في" => Token::In,
305 "طابق" => Token::Match,
306 "أعد" => Token::Return,
307 "امتلك" => Token::Own,
308 "أقرض" => Token::Lend,
309 "شارك" => Token::Share,
310 "انقل" => Token::Move,
311 "انسخ" => Token::Copy,
312 "غير_متزامن" => Token::Async,
313 "انتظر" => Token::Wait,
314 "بصفة" => Token::As,
315 "حيث" => Token::Where,
316 "انشر" => Token::Post,
317 "أعط" => Token::Give,
318 "يلائم" => Token::Fit,
319 "شكل" => Token::Form,
320 "اختر" => Token::Choose,
321 "يمكن" => Token::Can,
322 "غيّر" => Token::Change,
323 "توقف" => Token::Stop,
324 "مرة_أخرى" => Token::Again,
325 "حاول" => Token::Try,
326 "متأكد" => Token::Sure,
327 "ربما" => Token::Maybe,
328 "نقي" => Token::Pure,
329 "أنشئ" => Token::Spawn,
330 "تمام" => Token::Ok,
331 "سيء" => Token::Bad,
332 "لا_شيء" => Token::None,
333 "صحيح" => Token::Bool(true),
334 "خطأ" => Token::Bool(false),
335 "پیوند" => Token::Bind,
337 "انجام" => Token::Do,
338 "تابع" => Token::Fn,
339 "ماژول" => Token::Mod,
340 "استفاده" => Token::Use,
342 "اگر" => Token::If,
343 "وگرنه" => Token::Else,
344 "هنگامی" => Token::While,
345 "برای" => Token::For,
346 "در" => Token::In,
347 "تطبیق" => Token::Match,
348 "بازگشت" => Token::Return,
349 "مالک" => Token::Own,
350 "قرض" => Token::Lend,
351 "اشتراک" => Token::Share,
352 "انتقال" => Token::Move,
353 "کپی" => Token::Copy,
354 "ناهمگام" => Token::Async,
355 "انتظار" => Token::Wait,
356 "به_عنوان" => Token::As,
357 "جایی_که" => Token::Where,
358 "ارسال" => Token::Post,
359 "بده" => Token::Give,
360 "تناسب" => Token::Fit,
361 "ساختار" => Token::Form,
362 "انتخاب" => Token::Choose,
363 "امکان" => Token::Can,
364 "تغییر" => Token::Change,
365 "دوباره" => Token::Again,
366 "تلاش" => Token::Try,
367 "مطمئن" => Token::Sure,
368 "شاید" => Token::Maybe,
369 "خالص" => Token::Pure,
370 "ایجاد" => Token::Spawn,
371 "تایید" => Token::Ok,
372 "هیچ" => Token::None,
373 "درست" => Token::Bool(true),
374 "نادرست" => Token::Bool(false),
375 "קשר" => Token::Bind,
377 "בצע" => Token::Do,
378 "פונקציה" => Token::Fn,
379 "מודול" => Token::Mod,
380 "סוג" => Token::Type,
381 "השתמש" => Token::Use,
382 "אם" => Token::If,
383 "אחרת" => Token::Else,
384 "כל_עוד" => Token::While,
385 "עבור" => Token::For,
386 "בתוך" => Token::In,
387 "התאמה" => Token::Match,
388 "החזר" => Token::Return,
389 "בעל" => Token::Own,
390 "השאלה" => Token::Lend,
391 "שתף" => Token::Share,
392 "הזז" => Token::Move,
393 "העתק" => Token::Copy,
394 "אסינכרוני" => Token::Async,
395 "המתן" => Token::Wait,
396 "בתור" => Token::As,
397 "היכן" => Token::Where,
398 "פרסם" => Token::Post,
399 "תן" => Token::Give,
400 "מתאים" => Token::Fit,
401 "צורה" => Token::Form,
402 "בחר" => Token::Choose,
403 "יכול" => Token::Can,
404 "שנה" => Token::Change,
405 "עצור" => Token::Stop,
406 "שוב" => Token::Again,
407 "נסה" => Token::Try,
408 "בטוח" => Token::Sure,
409 "אולי" => Token::Maybe,
410 "טהור" => Token::Pure,
411 "צור" => Token::Spawn,
412 "בסדר" => Token::Ok,
413 "רע" => Token::Bad,
414 "כלום" => Token::None,
415 "אמת" => Token::Bool(true),
416 "שקר" => Token::Bool(false),
417 "باندھو" => Token::Bind,
419 "کرو" => Token::Do,
420 "تفاعل" => Token::Fn,
421 "ماڈیول" => Token::Mod,
422 "قسم" => Token::Type,
423 "استعمال" => Token::Use,
424 "ورنہ" => Token::Else,
426 "جب_تک" => Token::While,
427 "کے_لیے" => Token::For,
428 "میں" => Token::In,
429 "مطابقت" => Token::Match,
430 "واپس" => Token::Return,
431 "ادھار" => Token::Lend,
433 "شراکت" => Token::Share,
434 "منتقل" => Token::Move,
435 "نقل" => Token::Copy,
436 "غیر_ہمزمان" => Token::Async,
437 "بطور" => Token::As,
439 "جہاں" => Token::Where,
440 "شائع" => Token::Post,
441 "دو" => Token::Give,
442 "موزوں" => Token::Fit,
443 "شکل" => Token::Form,
444 "چنو" => Token::Choose,
445 "قابل" => Token::Can,
446 "تبدیل" => Token::Change,
447 "رکو" => Token::Stop,
448 "دوبارہ" => Token::Again,
449 "کوشش" => Token::Try,
450 "یقینی" => Token::Sure,
451 "پیدا" => Token::Spawn,
454 "ٹھیک" => Token::Ok,
455 "برا" => Token::Bad,
456 "کچھ_نہیں" => Token::None,
457 "سچ" => Token::Bool(true),
458 "جھوٹ" => Token::Bool(false),
459 "enlazar" => Token::Bind,
461 "hacer" => Token::Do,
462 "si" => Token::If,
463 "sino" => Token::Else,
464 "mientras" => Token::While,
465 "para" => Token::For,
466 "retornar" => Token::Return,
467 "verdadero" => Token::Bool(true),
468 "falso" => Token::Bool(false),
469 "lier" => Token::Bind,
471 "faire" => Token::Do,
472 "func" | "fonction" => Token::Fn,
473 "module" => Token::Mod,
474 "sinon" => Token::Else,
475 "tantque" | "tant_que" => Token::While,
476 "pour" => Token::For,
477 "dans" => Token::In,
478 "correspondre" => Token::Match,
479 "retourner" => Token::Return,
480 "posséder" => Token::Own,
481 "prêter" => Token::Lend,
482 "partager" => Token::Share,
483 "déplacer" => Token::Move,
484 "copier" => Token::Copy,
485 "asynchrone" => Token::Async,
486 "attendre" => Token::Wait,
487 "comme" => Token::As,
488 "où" => Token::Where,
489 "publier" => Token::Post,
490 "donner" => Token::Give,
491 "convenir" => Token::Fit,
492 "forme" => Token::Form,
493 "choisir" => Token::Choose,
494 "peut" => Token::Can,
495 "changer" => Token::Change,
496 "arrêter" => Token::Stop,
497 "encore" => Token::Again,
498 "essayer" => Token::Try,
499 "sûr" => Token::Sure,
500 "peut_être" => Token::Maybe,
501 "pur" => Token::Pure,
502 "engendrer" => Token::Spawn,
503 "bon" => Token::Ok,
504 "mauvais" => Token::Bad,
505 "rien" => Token::None,
506 "vrai" => Token::Bool(true),
507 "faux" => Token::Bool(false),
508 "binden" => Token::Bind,
510 "machen" => Token::Do,
511 "funktion" => Token::Fn,
512 "modul" => Token::Mod,
513 "typ" => Token::Type,
514 "verwenden" => Token::Use,
515 "wenn" => Token::If,
516 "sonst" => Token::Else,
517 "solange" => Token::While,
518 "für" => Token::For,
519 "abgleichen" => Token::Match,
520 "zurück" => Token::Return,
521 "besitzen" => Token::Own,
522 "leihen" => Token::Lend,
523 "teilen" => Token::Share,
524 "bewegen" => Token::Move,
525 "kopieren" => Token::Copy,
526 "asynchron" => Token::Async,
527 "warten" => Token::Wait,
528 "als" => Token::As,
529 "wobei" => Token::Where,
530 "veröffentlichen" => Token::Post,
531 "geben" => Token::Give,
532 "passen" => Token::Fit,
533 "wählen" => Token::Choose,
534 "kann" => Token::Can,
535 "ändern" => Token::Change,
536 "stoppen" => Token::Stop,
537 "wieder" => Token::Again,
538 "versuchen" => Token::Try,
539 "sicher" => Token::Sure,
540 "vielleicht" => Token::Maybe,
541 "rein" => Token::Pure,
542 "erzeugen" => Token::Spawn,
543 "gut" => Token::Ok,
544 "schlecht" => Token::Bad,
545 "nichts" => Token::None,
546 "wahr" => Token::Bool(true),
547 "falsch" => Token::Bool(false),
548 "ligar" => Token::Bind,
550 "fazer" => Token::Do,
551 "se" => Token::If,
552 "senão" => Token::Else,
553 "enquanto" => Token::While,
554 "verdadeiro" => Token::Bool(true),
555 other => Token::Ident(other.to_string()),
557 }
558 }
559
560 pub fn next_token(&mut self) -> Option<Token> {
561 self.skip_whitespace_and_comments();
562 let ch = self.peek()?;
563
564 if ch == '"' {
566 return Some(self.lex_string());
567 }
568
569 if ch.is_ascii_digit() {
571 return Some(self.lex_number());
572 }
573
574 if ch.is_alphabetic() || ch == '_' || is_unicode_combining(ch) {
576 return Some(self.lex_word());
577 }
578
579 let rest = self.rest();
581
582 if rest.starts_with("..") {
584 self.advance();
585 self.advance();
586 return Some(Token::DotDot);
587 }
588 if rest.starts_with("::") {
590 self.advance();
591 self.advance();
592 return Some(Token::ColonColon);
593 }
594 if rest.starts_with("==") {
596 self.advance();
597 self.advance();
598 return Some(Token::EqEq);
599 }
600 if rest.starts_with("!=") {
602 self.advance();
603 self.advance();
604 return Some(Token::Ne);
605 }
606 if rest.starts_with("<=") {
608 self.advance();
609 self.advance();
610 return Some(Token::Le);
611 }
612 if rest.starts_with(">=") {
614 self.advance();
615 self.advance();
616 return Some(Token::Ge);
617 }
618 if rest.starts_with("->") {
620 self.advance();
621 self.advance();
622 return Some(Token::Arrow);
623 }
624 if rest.starts_with("=>") {
626 self.advance();
627 self.advance();
628 return Some(Token::FatArrow);
629 }
630 if rest.starts_with("&&") {
632 self.advance();
633 self.advance();
634 return Some(Token::And);
635 }
636 if rest.starts_with("||") {
638 self.advance();
639 self.advance();
640 return Some(Token::Or);
641 }
642
643 self.advance();
645 Some(match ch {
646 '=' => Token::Eq,
647 '<' => Token::Lt,
648 '>' => Token::Gt,
649 '!' => Token::Not,
650 '+' => Token::Plus,
651 '-' => Token::Minus,
652 '*' => Token::Star,
653 '/' => Token::Slash,
654 '%' => Token::Percent,
655 '.' => Token::Dot,
656 '&' => Token::Ampersand,
657 '(' => Token::LParen,
658 ')' => Token::RParen,
659 '{' => Token::LBrace,
660 '}' => Token::RBrace,
661 '[' => Token::LBracket,
662 ']' => Token::RBracket,
663 ',' => Token::Comma,
664 ':' => Token::Colon,
665 ';' => Token::Semicolon,
666 '|' => Token::Or, c => Token::Error(c.to_string()),
668 })
669 }
670}
671
672fn is_unicode_combining(c: char) -> bool {
676 let cp = c as u32;
677 matches!(cp,
678 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 )
714}