1use logos::Logos;
4
5#[derive(Logos, Debug, Clone, PartialEq, Eq, Hash)]
7#[logos(skip r"[ \t\r\n]+")]
8#[logos(skip r"//[^\n]*")]
9pub enum Token {
10 #[token("agent")]
14 KwAgent,
15
16 #[token("belief")]
17 KwBelief,
18
19 #[token("on")]
20 KwOn,
21
22 #[token("start")]
23 KwStart,
24
25 #[token("stop")]
26 KwStop,
27
28 #[token("message")]
29 KwMessage,
30
31 #[token("divine")]
32 KwDivine,
33
34 #[token("summon")]
35 KwSummon,
36
37 #[token("await")]
38 KwAwait,
39
40 #[token("send")]
41 KwSend,
42
43 #[token("yield")]
44 KwYield,
45
46 #[token("run")]
47 KwRun,
48
49 #[token("fn")]
50 KwFn,
51
52 #[token("let")]
53 KwLet,
54
55 #[token("return")]
56 KwReturn,
57
58 #[token("if")]
59 KwIf,
60
61 #[token("else")]
62 KwElse,
63
64 #[token("for")]
65 KwFor,
66
67 #[token("while")]
68 KwWhile,
69
70 #[token("loop")]
71 KwLoop,
72
73 #[token("break")]
74 KwBreak,
75
76 #[token("in")]
77 KwIn,
78
79 #[token("self")]
80 KwSelf,
81
82 #[token("true")]
83 KwTrue,
84
85 #[token("false")]
86 KwFalse,
87
88 #[token("mod")]
89 KwMod,
90
91 #[token("use")]
92 KwUse,
93
94 #[token("pub")]
95 KwPub,
96
97 #[token("as")]
98 KwAs,
99
100 #[token("super")]
101 KwSuper,
102
103 #[token("record")]
104 KwRecord,
105
106 #[token("enum")]
107 KwEnum,
108
109 #[token("match")]
110 KwMatch,
111
112 #[token("const")]
113 KwConst,
114
115 #[token("receives")]
116 KwReceives,
117
118 #[token("receive")]
119 KwReceive,
120
121 #[token("fail")]
122 KwFail,
123
124 #[token("fails")]
125 KwFails,
126
127 #[token("timeout")]
128 KwTimeout,
129
130 #[token("retry")]
131 KwRetry,
132
133 #[token("delay")]
134 KwDelay,
135
136 #[token("try")]
137 KwTry,
138
139 #[token("catch")]
140 KwCatch,
141
142 #[token("error")]
143 KwError,
144
145 #[token("tool")]
146 KwTool,
147
148 #[token("test")]
150 KwTest,
151
152 #[token("mock")]
154 KwMock,
155
156 #[token("trace")]
158 KwTrace,
159
160 #[token("Int")]
164 TyInt,
165
166 #[token("Float")]
167 TyFloat,
168
169 #[token("Bool")]
170 TyBool,
171
172 #[token("String")]
173 TyString,
174
175 #[token("Unit")]
176 TyUnit,
177
178 #[token("List")]
179 TyList,
180
181 #[token("Option")]
182 TyOption,
183
184 #[token("Oracle")]
185 TyOracle,
186
187 #[token("Agent")]
188 TyAgent,
189
190 #[token("Error")]
191 TyError,
192
193 #[token("ErrorKind")]
194 TyErrorKind,
195
196 #[token("Fn")]
198 TyFn,
199
200 #[token("Map")]
202 TyMap,
203
204 #[token("Result")]
206 TyResult,
207
208 #[regex(r"-?[0-9]+", priority = 2)]
213 IntLit,
214
215 #[regex(r"-?[0-9]+\.[0-9]+")]
217 FloatLit,
218
219 #[regex(r#""([^"\\]|\\.)*""#)]
224 #[regex(r#"'([^'\\]|\\.)*'"#)]
225 StringLit,
226
227 #[regex(r"[a-zA-Z_][a-zA-Z0-9_]*")]
232 Ident,
233
234 #[token("{")]
238 LBrace,
239
240 #[token("}")]
241 RBrace,
242
243 #[token("(")]
244 LParen,
245
246 #[token(")")]
247 RParen,
248
249 #[token("[")]
250 LBracket,
251
252 #[token("]")]
253 RBracket,
254
255 #[token(",")]
256 Comma,
257
258 #[token("::")]
259 ColonColon,
260
261 #[token(":")]
262 Colon,
263
264 #[token(".")]
265 Dot,
266
267 #[token("->")]
268 Arrow,
269
270 #[token("=>")]
271 FatArrow,
272
273 #[token("@")]
275 At,
276
277 #[token("=")]
281 Eq,
282
283 #[token("==")]
284 EqEq,
285
286 #[token("!=")]
287 Ne,
288
289 #[token("<")]
290 Lt,
291
292 #[token(">")]
293 Gt,
294
295 #[token("<=")]
296 Le,
297
298 #[token(">=")]
299 Ge,
300
301 #[token("+")]
302 Plus,
303
304 #[token("-")]
305 Minus,
306
307 #[token("*")]
308 Star,
309
310 #[token("/")]
311 Slash,
312
313 #[token("!")]
314 Bang,
315
316 #[token("&&")]
317 And,
318
319 #[token("||")]
320 Or,
321
322 #[token("|")]
324 Pipe,
325
326 #[token("++")]
328 PlusPlus,
329
330 #[token("%")]
332 Percent,
333
334 #[token(";")]
336 Semicolon,
337}
338
339impl Token {
340 #[must_use]
342 pub fn is_keyword(&self) -> bool {
343 matches!(
344 self,
345 Token::KwAgent
346 | Token::KwBelief
347 | Token::KwOn
348 | Token::KwStart
349 | Token::KwStop
350 | Token::KwMessage
351 | Token::KwDivine
352 | Token::KwSummon
353 | Token::KwAwait
354 | Token::KwSend
355 | Token::KwYield
356 | Token::KwRun
357 | Token::KwFn
358 | Token::KwLet
359 | Token::KwReturn
360 | Token::KwIf
361 | Token::KwElse
362 | Token::KwFor
363 | Token::KwWhile
364 | Token::KwLoop
365 | Token::KwBreak
366 | Token::KwIn
367 | Token::KwSelf
368 | Token::KwTrue
369 | Token::KwFalse
370 | Token::KwMod
371 | Token::KwUse
372 | Token::KwPub
373 | Token::KwAs
374 | Token::KwSuper
375 | Token::KwRecord
376 | Token::KwEnum
377 | Token::KwMatch
378 | Token::KwConst
379 | Token::KwReceives
380 | Token::KwReceive
381 | Token::KwFail
382 | Token::KwFails
383 | Token::KwTimeout
384 | Token::KwRetry
385 | Token::KwDelay
386 | Token::KwTry
387 | Token::KwCatch
388 | Token::KwError
389 | Token::KwTool
390 | Token::KwTrace
391 )
392 }
393
394 #[must_use]
396 pub fn is_type_keyword(&self) -> bool {
397 matches!(
398 self,
399 Token::TyInt
400 | Token::TyFloat
401 | Token::TyBool
402 | Token::TyString
403 | Token::TyUnit
404 | Token::TyList
405 | Token::TyOption
406 | Token::TyOracle
407 | Token::TyAgent
408 | Token::TyError
409 | Token::TyErrorKind
410 | Token::TyFn
411 | Token::TyMap
412 | Token::TyResult
413 )
414 }
415
416 #[must_use]
418 pub fn is_literal(&self) -> bool {
419 matches!(
420 self,
421 Token::IntLit | Token::FloatLit | Token::StringLit | Token::KwTrue | Token::KwFalse
422 )
423 }
424
425 #[must_use]
427 pub fn is_operator(&self) -> bool {
428 matches!(
429 self,
430 Token::Eq
431 | Token::EqEq
432 | Token::Ne
433 | Token::Lt
434 | Token::Gt
435 | Token::Le
436 | Token::Ge
437 | Token::Plus
438 | Token::Minus
439 | Token::Star
440 | Token::Slash
441 | Token::Percent
442 | Token::Bang
443 | Token::And
444 | Token::Or
445 | Token::PlusPlus
446 )
447 }
448}
449
450impl std::fmt::Display for Token {
451 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
452 match self {
453 Token::KwAgent => write!(f, "agent"),
455 Token::KwBelief => write!(f, "belief"),
456 Token::KwOn => write!(f, "on"),
457 Token::KwStart => write!(f, "start"),
458 Token::KwStop => write!(f, "stop"),
459 Token::KwMessage => write!(f, "message"),
460 Token::KwDivine => write!(f, "divine"),
461 Token::KwSummon => write!(f, "summon"),
462 Token::KwAwait => write!(f, "await"),
463 Token::KwSend => write!(f, "send"),
464 Token::KwYield => write!(f, "yield"),
465 Token::KwRun => write!(f, "run"),
466 Token::KwFn => write!(f, "fn"),
467 Token::KwLet => write!(f, "let"),
468 Token::KwReturn => write!(f, "return"),
469 Token::KwIf => write!(f, "if"),
470 Token::KwElse => write!(f, "else"),
471 Token::KwFor => write!(f, "for"),
472 Token::KwWhile => write!(f, "while"),
473 Token::KwLoop => write!(f, "loop"),
474 Token::KwBreak => write!(f, "break"),
475 Token::KwIn => write!(f, "in"),
476 Token::KwSelf => write!(f, "self"),
477 Token::KwTrue => write!(f, "true"),
478 Token::KwFalse => write!(f, "false"),
479 Token::KwMod => write!(f, "mod"),
480 Token::KwUse => write!(f, "use"),
481 Token::KwPub => write!(f, "pub"),
482 Token::KwAs => write!(f, "as"),
483 Token::KwSuper => write!(f, "super"),
484 Token::KwRecord => write!(f, "record"),
485 Token::KwEnum => write!(f, "enum"),
486 Token::KwMatch => write!(f, "match"),
487 Token::KwConst => write!(f, "const"),
488 Token::KwReceives => write!(f, "receives"),
489 Token::KwReceive => write!(f, "receive"),
490 Token::KwFail => write!(f, "fail"),
491 Token::KwFails => write!(f, "fails"),
492 Token::KwTimeout => write!(f, "timeout"),
493 Token::KwRetry => write!(f, "retry"),
494 Token::KwDelay => write!(f, "delay"),
495 Token::KwTry => write!(f, "try"),
496 Token::KwCatch => write!(f, "catch"),
497 Token::KwError => write!(f, "error"),
498 Token::KwTool => write!(f, "tool"),
499 Token::KwTest => write!(f, "test"),
500 Token::KwMock => write!(f, "mock"),
501 Token::KwTrace => write!(f, "trace"),
502
503 Token::TyInt => write!(f, "Int"),
505 Token::TyFloat => write!(f, "Float"),
506 Token::TyBool => write!(f, "Bool"),
507 Token::TyString => write!(f, "String"),
508 Token::TyUnit => write!(f, "Unit"),
509 Token::TyList => write!(f, "List"),
510 Token::TyOption => write!(f, "Option"),
511 Token::TyOracle => write!(f, "Oracle"),
512 Token::TyAgent => write!(f, "Agent"),
513 Token::TyError => write!(f, "Error"),
514 Token::TyErrorKind => write!(f, "ErrorKind"),
515 Token::TyFn => write!(f, "Fn"),
516 Token::TyMap => write!(f, "Map"),
517 Token::TyResult => write!(f, "Result"),
518
519 Token::IntLit => write!(f, "<int>"),
521 Token::FloatLit => write!(f, "<float>"),
522 Token::StringLit => write!(f, "<string>"),
523
524 Token::Ident => write!(f, "<ident>"),
526
527 Token::LBrace => write!(f, "{{"),
529 Token::RBrace => write!(f, "}}"),
530 Token::LParen => write!(f, "("),
531 Token::RParen => write!(f, ")"),
532 Token::LBracket => write!(f, "["),
533 Token::RBracket => write!(f, "]"),
534 Token::Comma => write!(f, ","),
535 Token::ColonColon => write!(f, "::"),
536 Token::Colon => write!(f, ":"),
537 Token::Dot => write!(f, "."),
538 Token::Arrow => write!(f, "->"),
539 Token::FatArrow => write!(f, "=>"),
540 Token::At => write!(f, "@"),
541
542 Token::Eq => write!(f, "="),
544 Token::EqEq => write!(f, "=="),
545 Token::Ne => write!(f, "!="),
546 Token::Lt => write!(f, "<"),
547 Token::Gt => write!(f, ">"),
548 Token::Le => write!(f, "<="),
549 Token::Ge => write!(f, ">="),
550 Token::Plus => write!(f, "+"),
551 Token::Minus => write!(f, "-"),
552 Token::Star => write!(f, "*"),
553 Token::Slash => write!(f, "/"),
554 Token::Bang => write!(f, "!"),
555 Token::And => write!(f, "&&"),
556 Token::Or => write!(f, "||"),
557 Token::Pipe => write!(f, "|"),
558 Token::PlusPlus => write!(f, "++"),
559 Token::Percent => write!(f, "%"),
560 Token::Semicolon => write!(f, ";"),
561 }
562 }
563}
564
565#[cfg(test)]
566mod tests {
567 use super::*;
568
569 #[test]
570 fn lex_keywords() {
571 let mut lexer = Token::lexer("agent belief on start stop message");
572 assert_eq!(lexer.next(), Some(Ok(Token::KwAgent)));
573 assert_eq!(lexer.next(), Some(Ok(Token::KwBelief)));
574 assert_eq!(lexer.next(), Some(Ok(Token::KwOn)));
575 assert_eq!(lexer.next(), Some(Ok(Token::KwStart)));
576 assert_eq!(lexer.next(), Some(Ok(Token::KwStop)));
577 assert_eq!(lexer.next(), Some(Ok(Token::KwMessage)));
578 assert_eq!(lexer.next(), None);
579 }
580
581 #[test]
582 fn lex_more_keywords() {
583 let mut lexer = Token::lexer(
584 "divine summon await send yield run fn let return if else for in self true false",
585 );
586 assert_eq!(lexer.next(), Some(Ok(Token::KwDivine)));
587 assert_eq!(lexer.next(), Some(Ok(Token::KwSummon)));
588 assert_eq!(lexer.next(), Some(Ok(Token::KwAwait)));
589 assert_eq!(lexer.next(), Some(Ok(Token::KwSend)));
590 assert_eq!(lexer.next(), Some(Ok(Token::KwYield)));
591 assert_eq!(lexer.next(), Some(Ok(Token::KwRun)));
592 assert_eq!(lexer.next(), Some(Ok(Token::KwFn)));
593 assert_eq!(lexer.next(), Some(Ok(Token::KwLet)));
594 assert_eq!(lexer.next(), Some(Ok(Token::KwReturn)));
595 assert_eq!(lexer.next(), Some(Ok(Token::KwIf)));
596 assert_eq!(lexer.next(), Some(Ok(Token::KwElse)));
597 assert_eq!(lexer.next(), Some(Ok(Token::KwFor)));
598 assert_eq!(lexer.next(), Some(Ok(Token::KwIn)));
599 assert_eq!(lexer.next(), Some(Ok(Token::KwSelf)));
600 assert_eq!(lexer.next(), Some(Ok(Token::KwTrue)));
601 assert_eq!(lexer.next(), Some(Ok(Token::KwFalse)));
602 assert_eq!(lexer.next(), None);
603 }
604
605 #[test]
606 fn lex_type_keywords() {
607 let mut lexer = Token::lexer("Int Float Bool String Unit List Option Oracle Agent");
608 assert_eq!(lexer.next(), Some(Ok(Token::TyInt)));
609 assert_eq!(lexer.next(), Some(Ok(Token::TyFloat)));
610 assert_eq!(lexer.next(), Some(Ok(Token::TyBool)));
611 assert_eq!(lexer.next(), Some(Ok(Token::TyString)));
612 assert_eq!(lexer.next(), Some(Ok(Token::TyUnit)));
613 assert_eq!(lexer.next(), Some(Ok(Token::TyList)));
614 assert_eq!(lexer.next(), Some(Ok(Token::TyOption)));
615 assert_eq!(lexer.next(), Some(Ok(Token::TyOracle)));
616 assert_eq!(lexer.next(), Some(Ok(Token::TyAgent)));
617 assert_eq!(lexer.next(), None);
618 }
619
620 #[test]
621 fn lex_integer_literals() {
622 let mut lexer = Token::lexer("42 -7 0 123456");
623 assert_eq!(lexer.next(), Some(Ok(Token::IntLit)));
624 assert_eq!(lexer.slice(), "42");
625 assert_eq!(lexer.next(), Some(Ok(Token::IntLit)));
626 assert_eq!(lexer.slice(), "-7");
627 assert_eq!(lexer.next(), Some(Ok(Token::IntLit)));
628 assert_eq!(lexer.slice(), "0");
629 assert_eq!(lexer.next(), Some(Ok(Token::IntLit)));
630 assert_eq!(lexer.slice(), "123456");
631 assert_eq!(lexer.next(), None);
632 }
633
634 #[test]
635 fn lex_float_literals() {
636 let mut lexer = Token::lexer("3.14 -0.5 0.0 123.456");
637 assert_eq!(lexer.next(), Some(Ok(Token::FloatLit)));
638 assert_eq!(lexer.slice(), "3.14");
639 assert_eq!(lexer.next(), Some(Ok(Token::FloatLit)));
640 assert_eq!(lexer.slice(), "-0.5");
641 assert_eq!(lexer.next(), Some(Ok(Token::FloatLit)));
642 assert_eq!(lexer.slice(), "0.0");
643 assert_eq!(lexer.next(), Some(Ok(Token::FloatLit)));
644 assert_eq!(lexer.slice(), "123.456");
645 assert_eq!(lexer.next(), None);
646 }
647
648 #[test]
649 fn lex_string_literals() {
650 let mut lexer = Token::lexer(r#""hello" "world" "with spaces""#);
651 assert_eq!(lexer.next(), Some(Ok(Token::StringLit)));
652 assert_eq!(lexer.slice(), r#""hello""#);
653 assert_eq!(lexer.next(), Some(Ok(Token::StringLit)));
654 assert_eq!(lexer.slice(), r#""world""#);
655 assert_eq!(lexer.next(), Some(Ok(Token::StringLit)));
656 assert_eq!(lexer.slice(), r#""with spaces""#);
657 assert_eq!(lexer.next(), None);
658 }
659
660 #[test]
661 fn lex_string_with_escapes() {
662 let mut lexer = Token::lexer(r#""hello\nworld" "tab\there" "quote\"here""#);
663 assert_eq!(lexer.next(), Some(Ok(Token::StringLit)));
664 assert_eq!(lexer.slice(), r#""hello\nworld""#);
665 assert_eq!(lexer.next(), Some(Ok(Token::StringLit)));
666 assert_eq!(lexer.slice(), r#""tab\there""#);
667 assert_eq!(lexer.next(), Some(Ok(Token::StringLit)));
668 assert_eq!(lexer.slice(), r#""quote\"here""#);
669 assert_eq!(lexer.next(), None);
670 }
671
672 #[test]
673 fn lex_identifiers() {
674 let mut lexer = Token::lexer("foo bar _private myAgent agent2");
675 assert_eq!(lexer.next(), Some(Ok(Token::Ident)));
676 assert_eq!(lexer.slice(), "foo");
677 assert_eq!(lexer.next(), Some(Ok(Token::Ident)));
678 assert_eq!(lexer.slice(), "bar");
679 assert_eq!(lexer.next(), Some(Ok(Token::Ident)));
680 assert_eq!(lexer.slice(), "_private");
681 assert_eq!(lexer.next(), Some(Ok(Token::Ident)));
682 assert_eq!(lexer.slice(), "myAgent");
683 assert_eq!(lexer.next(), Some(Ok(Token::Ident)));
684 assert_eq!(lexer.slice(), "agent2");
685 assert_eq!(lexer.next(), None);
686 }
687
688 #[test]
689 fn keyword_vs_identifier() {
690 let mut lexer = Token::lexer("agent agent_name agents");
692 assert_eq!(lexer.next(), Some(Ok(Token::KwAgent)));
693 assert_eq!(lexer.next(), Some(Ok(Token::Ident)));
694 assert_eq!(lexer.slice(), "agent_name");
695 assert_eq!(lexer.next(), Some(Ok(Token::Ident)));
696 assert_eq!(lexer.slice(), "agents");
697 assert_eq!(lexer.next(), None);
698 }
699
700 #[test]
701 fn lex_punctuation() {
702 let mut lexer = Token::lexer("{ } ( ) [ ] , : . ->");
703 assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
704 assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
705 assert_eq!(lexer.next(), Some(Ok(Token::LParen)));
706 assert_eq!(lexer.next(), Some(Ok(Token::RParen)));
707 assert_eq!(lexer.next(), Some(Ok(Token::LBracket)));
708 assert_eq!(lexer.next(), Some(Ok(Token::RBracket)));
709 assert_eq!(lexer.next(), Some(Ok(Token::Comma)));
710 assert_eq!(lexer.next(), Some(Ok(Token::Colon)));
711 assert_eq!(lexer.next(), Some(Ok(Token::Dot)));
712 assert_eq!(lexer.next(), Some(Ok(Token::Arrow)));
713 assert_eq!(lexer.next(), None);
714 }
715
716 #[test]
717 fn lex_operators() {
718 let mut lexer = Token::lexer("= == != < > <= >= + - * / % ! && || ++");
719 assert_eq!(lexer.next(), Some(Ok(Token::Eq)));
720 assert_eq!(lexer.next(), Some(Ok(Token::EqEq)));
721 assert_eq!(lexer.next(), Some(Ok(Token::Ne)));
722 assert_eq!(lexer.next(), Some(Ok(Token::Lt)));
723 assert_eq!(lexer.next(), Some(Ok(Token::Gt)));
724 assert_eq!(lexer.next(), Some(Ok(Token::Le)));
725 assert_eq!(lexer.next(), Some(Ok(Token::Ge)));
726 assert_eq!(lexer.next(), Some(Ok(Token::Plus)));
727 assert_eq!(lexer.next(), Some(Ok(Token::Minus)));
728 assert_eq!(lexer.next(), Some(Ok(Token::Star)));
729 assert_eq!(lexer.next(), Some(Ok(Token::Slash)));
730 assert_eq!(lexer.next(), Some(Ok(Token::Percent)));
731 assert_eq!(lexer.next(), Some(Ok(Token::Bang)));
732 assert_eq!(lexer.next(), Some(Ok(Token::And)));
733 assert_eq!(lexer.next(), Some(Ok(Token::Or)));
734 assert_eq!(lexer.next(), Some(Ok(Token::PlusPlus)));
735 assert_eq!(lexer.next(), None);
736 }
737
738 #[test]
739 fn skip_whitespace() {
740 let mut lexer = Token::lexer(" agent belief\n\ttrue ");
741 assert_eq!(lexer.next(), Some(Ok(Token::KwAgent)));
742 assert_eq!(lexer.next(), Some(Ok(Token::KwBelief)));
743 assert_eq!(lexer.next(), Some(Ok(Token::KwTrue)));
744 assert_eq!(lexer.next(), None);
745 }
746
747 #[test]
748 fn skip_comments() {
749 let mut lexer = Token::lexer("agent // this is a comment\nbelief");
750 assert_eq!(lexer.next(), Some(Ok(Token::KwAgent)));
751 assert_eq!(lexer.next(), Some(Ok(Token::KwBelief)));
752 assert_eq!(lexer.next(), None);
753 }
754
755 #[test]
756 fn comment_at_end() {
757 let mut lexer = Token::lexer("agent // comment at end");
758 assert_eq!(lexer.next(), Some(Ok(Token::KwAgent)));
759 assert_eq!(lexer.next(), None);
760 }
761
762 #[test]
763 fn lex_agent_declaration() {
764 let source = r#"
765 agent Researcher {
766 belief topic: String
767
768 on start {
769 let result: Oracle<String> = divine("test")
770 yield(result)
771 }
772 }
773 "#;
774 let tokens: Vec<_> = Token::lexer(source)
775 .map(|r| r.expect("valid token"))
776 .collect();
777
778 assert_eq!(tokens[0], Token::KwAgent);
779 assert_eq!(tokens[1], Token::Ident); assert_eq!(tokens[2], Token::LBrace);
781 assert_eq!(tokens[3], Token::KwBelief);
782 assert_eq!(tokens[4], Token::Ident); assert_eq!(tokens[5], Token::Colon);
784 assert_eq!(tokens[6], Token::TyString);
785 assert_eq!(tokens[7], Token::KwOn);
786 assert_eq!(tokens[8], Token::KwStart);
787 assert_eq!(tokens[9], Token::LBrace);
788 assert_eq!(tokens[10], Token::KwLet);
789 }
790
791 #[test]
792 fn is_keyword_helper() {
793 assert!(Token::KwAgent.is_keyword());
794 assert!(Token::KwLet.is_keyword());
795 assert!(!Token::TyInt.is_keyword());
796 assert!(!Token::Ident.is_keyword());
797 }
798
799 #[test]
800 fn is_type_keyword_helper() {
801 assert!(Token::TyInt.is_type_keyword());
802 assert!(Token::TyAgent.is_type_keyword());
803 assert!(!Token::KwAgent.is_type_keyword());
804 assert!(!Token::Ident.is_type_keyword());
805 }
806
807 #[test]
808 fn is_literal_helper() {
809 assert!(Token::IntLit.is_literal());
810 assert!(Token::FloatLit.is_literal());
811 assert!(Token::StringLit.is_literal());
812 assert!(Token::KwTrue.is_literal());
813 assert!(Token::KwFalse.is_literal());
814 assert!(!Token::Ident.is_literal());
815 }
816
817 #[test]
818 fn is_operator_helper() {
819 assert!(Token::Plus.is_operator());
820 assert!(Token::EqEq.is_operator());
821 assert!(Token::PlusPlus.is_operator());
822 assert!(!Token::LBrace.is_operator());
823 assert!(!Token::Ident.is_operator());
824 }
825
826 #[test]
827 fn lex_module_keywords() {
828 let mut lexer = Token::lexer("mod use pub as super");
829 assert_eq!(lexer.next(), Some(Ok(Token::KwMod)));
830 assert_eq!(lexer.next(), Some(Ok(Token::KwUse)));
831 assert_eq!(lexer.next(), Some(Ok(Token::KwPub)));
832 assert_eq!(lexer.next(), Some(Ok(Token::KwAs)));
833 assert_eq!(lexer.next(), Some(Ok(Token::KwSuper)));
834 assert_eq!(lexer.next(), None);
835 }
836
837 #[test]
838 fn lex_path_separator() {
839 let mut lexer = Token::lexer("agents::Researcher");
840 assert_eq!(lexer.next(), Some(Ok(Token::Ident)));
841 assert_eq!(lexer.slice(), "agents");
842 assert_eq!(lexer.next(), Some(Ok(Token::ColonColon)));
843 assert_eq!(lexer.next(), Some(Ok(Token::Ident)));
844 assert_eq!(lexer.slice(), "Researcher");
845 assert_eq!(lexer.next(), None);
846 }
847
848 #[test]
849 fn lex_use_statement() {
850 let mut lexer = Token::lexer("use agents::{Researcher, Coordinator as Coord}");
851 assert_eq!(lexer.next(), Some(Ok(Token::KwUse)));
852 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::ColonColon)));
854 assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
855 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Comma)));
857 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::KwAs)));
859 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
861 assert_eq!(lexer.next(), None);
862 }
863
864 #[test]
865 fn lex_pub_agent() {
866 let mut lexer = Token::lexer("pub agent Researcher");
867 assert_eq!(lexer.next(), Some(Ok(Token::KwPub)));
868 assert_eq!(lexer.next(), Some(Ok(Token::KwAgent)));
869 assert_eq!(lexer.next(), Some(Ok(Token::Ident)));
870 assert_eq!(lexer.next(), None);
871 }
872
873 #[test]
874 fn token_display() {
875 assert_eq!(format!("{}", Token::KwAgent), "agent");
876 assert_eq!(format!("{}", Token::TyInt), "Int");
877 assert_eq!(format!("{}", Token::IntLit), "<int>");
878 assert_eq!(format!("{}", Token::Ident), "<ident>");
879 assert_eq!(format!("{}", Token::LBrace), "{");
880 assert_eq!(format!("{}", Token::PlusPlus), "++");
881 }
882
883 #[test]
884 fn lex_type_keywords_record_enum_match_const() {
885 let mut lexer = Token::lexer("record enum match const");
886 assert_eq!(lexer.next(), Some(Ok(Token::KwRecord)));
887 assert_eq!(lexer.next(), Some(Ok(Token::KwEnum)));
888 assert_eq!(lexer.next(), Some(Ok(Token::KwMatch)));
889 assert_eq!(lexer.next(), Some(Ok(Token::KwConst)));
890 assert_eq!(lexer.next(), None);
891 }
892
893 #[test]
894 fn lex_fat_arrow() {
895 let mut lexer = Token::lexer("=> -> =");
896 assert_eq!(lexer.next(), Some(Ok(Token::FatArrow)));
897 assert_eq!(lexer.next(), Some(Ok(Token::Arrow)));
898 assert_eq!(lexer.next(), Some(Ok(Token::Eq)));
899 assert_eq!(lexer.next(), None);
900 }
901
902 #[test]
903 fn lex_match_expression() {
904 let mut lexer = Token::lexer("match status { Active => 1, Inactive => 0 }");
905 assert_eq!(lexer.next(), Some(Ok(Token::KwMatch)));
906 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
908 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::FatArrow)));
910 assert_eq!(lexer.next(), Some(Ok(Token::IntLit))); assert_eq!(lexer.next(), Some(Ok(Token::Comma)));
912 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::FatArrow)));
914 assert_eq!(lexer.next(), Some(Ok(Token::IntLit))); assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
916 assert_eq!(lexer.next(), None);
917 }
918
919 #[test]
920 fn lex_record_declaration() {
921 let mut lexer = Token::lexer("record Point { x: Int, y: Int }");
922 assert_eq!(lexer.next(), Some(Ok(Token::KwRecord)));
923 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
925 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Colon)));
927 assert_eq!(lexer.next(), Some(Ok(Token::TyInt)));
928 assert_eq!(lexer.next(), Some(Ok(Token::Comma)));
929 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Colon)));
931 assert_eq!(lexer.next(), Some(Ok(Token::TyInt)));
932 assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
933 assert_eq!(lexer.next(), None);
934 }
935
936 #[test]
937 fn lex_enum_declaration() {
938 let mut lexer = Token::lexer("enum Status { Active, Pending, Done }");
939 assert_eq!(lexer.next(), Some(Ok(Token::KwEnum)));
940 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
942 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Comma)));
944 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Comma)));
946 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
948 assert_eq!(lexer.next(), None);
949 }
950
951 #[test]
952 fn lex_const_declaration() {
953 let mut lexer = Token::lexer("const MAX_RETRIES: Int = 3");
954 assert_eq!(lexer.next(), Some(Ok(Token::KwConst)));
955 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Colon)));
957 assert_eq!(lexer.next(), Some(Ok(Token::TyInt)));
958 assert_eq!(lexer.next(), Some(Ok(Token::Eq)));
959 assert_eq!(lexer.next(), Some(Ok(Token::IntLit))); assert_eq!(lexer.next(), None);
961 }
962
963 #[test]
964 fn new_keywords_are_keywords() {
965 assert!(Token::KwRecord.is_keyword());
966 assert!(Token::KwEnum.is_keyword());
967 assert!(Token::KwMatch.is_keyword());
968 assert!(Token::KwConst.is_keyword());
969 }
970
971 #[test]
972 fn lex_loop_break() {
973 let mut lexer = Token::lexer("loop { break }");
974 assert_eq!(lexer.next(), Some(Ok(Token::KwLoop)));
975 assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
976 assert_eq!(lexer.next(), Some(Ok(Token::KwBreak)));
977 assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
978 assert_eq!(lexer.next(), None);
979 }
980
981 #[test]
982 fn lex_receives_receive() {
983 let mut lexer = Token::lexer("agent Worker receives WorkerMsg { receive }");
984 assert_eq!(lexer.next(), Some(Ok(Token::KwAgent)));
985 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::KwReceives)));
987 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
989 assert_eq!(lexer.next(), Some(Ok(Token::KwReceive)));
990 assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
991 assert_eq!(lexer.next(), None);
992 }
993
994 #[test]
995 fn rfc6_keywords_are_keywords() {
996 assert!(Token::KwLoop.is_keyword());
997 assert!(Token::KwBreak.is_keyword());
998 assert!(Token::KwReceives.is_keyword());
999 assert!(Token::KwReceive.is_keyword());
1000 }
1001
1002 #[test]
1003 fn lex_error_handling_keywords() {
1004 let mut lexer = Token::lexer("fails try catch error");
1005 assert_eq!(lexer.next(), Some(Ok(Token::KwFails)));
1006 assert_eq!(lexer.next(), Some(Ok(Token::KwTry)));
1007 assert_eq!(lexer.next(), Some(Ok(Token::KwCatch)));
1008 assert_eq!(lexer.next(), Some(Ok(Token::KwError)));
1009 assert_eq!(lexer.next(), None);
1010 }
1011
1012 #[test]
1013 fn lex_try_catch_expression() {
1014 let mut lexer = Token::lexer("let x = try divine(prompt) catch { fallback }");
1015 assert_eq!(lexer.next(), Some(Ok(Token::KwLet)));
1016 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Eq)));
1018 assert_eq!(lexer.next(), Some(Ok(Token::KwTry)));
1019 assert_eq!(lexer.next(), Some(Ok(Token::KwDivine)));
1020 assert_eq!(lexer.next(), Some(Ok(Token::LParen)));
1021 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::RParen)));
1023 assert_eq!(lexer.next(), Some(Ok(Token::KwCatch)));
1024 assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
1025 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
1027 assert_eq!(lexer.next(), None);
1028 }
1029
1030 #[test]
1031 fn lex_fails_function() {
1032 let mut lexer = Token::lexer("fn fetch(url: String) -> String fails { }");
1033 assert_eq!(lexer.next(), Some(Ok(Token::KwFn)));
1034 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::LParen)));
1036 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Colon)));
1038 assert_eq!(lexer.next(), Some(Ok(Token::TyString)));
1039 assert_eq!(lexer.next(), Some(Ok(Token::RParen)));
1040 assert_eq!(lexer.next(), Some(Ok(Token::Arrow)));
1041 assert_eq!(lexer.next(), Some(Ok(Token::TyString)));
1042 assert_eq!(lexer.next(), Some(Ok(Token::KwFails)));
1043 assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
1044 assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
1045 assert_eq!(lexer.next(), None);
1046 }
1047
1048 #[test]
1049 fn lex_on_error_handler() {
1050 let mut lexer = Token::lexer("on error(e) { yield(fallback) }");
1051 assert_eq!(lexer.next(), Some(Ok(Token::KwOn)));
1052 assert_eq!(lexer.next(), Some(Ok(Token::KwError)));
1053 assert_eq!(lexer.next(), Some(Ok(Token::LParen)));
1054 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::RParen)));
1056 assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
1057 assert_eq!(lexer.next(), Some(Ok(Token::KwYield)));
1058 assert_eq!(lexer.next(), Some(Ok(Token::LParen)));
1059 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::RParen)));
1061 assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
1062 assert_eq!(lexer.next(), None);
1063 }
1064
1065 #[test]
1066 fn rfc7_keywords_are_keywords() {
1067 assert!(Token::KwFail.is_keyword());
1068 assert!(Token::KwFails.is_keyword());
1069 assert!(Token::KwTry.is_keyword());
1070 assert!(Token::KwCatch.is_keyword());
1071 assert!(Token::KwError.is_keyword());
1072 }
1073
1074 #[test]
1075 fn lex_fail_expression() {
1076 let mut lexer = Token::lexer("fail \"error message\"");
1077 assert_eq!(lexer.next(), Some(Ok(Token::KwFail)));
1078 assert_eq!(lexer.next(), Some(Ok(Token::StringLit)));
1079 assert_eq!(lexer.next(), None);
1080 }
1081
1082 #[test]
1087 fn lex_closure_syntax() {
1088 let mut lexer = Token::lexer("|x: Int| x + 1");
1090 assert_eq!(lexer.next(), Some(Ok(Token::Pipe)));
1091 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Colon)));
1093 assert_eq!(lexer.next(), Some(Ok(Token::TyInt)));
1094 assert_eq!(lexer.next(), Some(Ok(Token::Pipe)));
1095 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Plus)));
1097 assert_eq!(lexer.next(), Some(Ok(Token::IntLit)));
1098 assert_eq!(lexer.next(), None);
1099 }
1100
1101 #[test]
1102 fn lex_empty_closure() {
1103 let mut lexer = Token::lexer("|| 42");
1105 assert_eq!(lexer.next(), Some(Ok(Token::Or))); assert_eq!(lexer.next(), Some(Ok(Token::IntLit)));
1107 assert_eq!(lexer.next(), None);
1108 }
1109
1110 #[test]
1111 fn lex_fn_type() {
1112 let mut lexer = Token::lexer("Fn(Int, String) -> Bool");
1114 assert_eq!(lexer.next(), Some(Ok(Token::TyFn)));
1115 assert_eq!(lexer.next(), Some(Ok(Token::LParen)));
1116 assert_eq!(lexer.next(), Some(Ok(Token::TyInt)));
1117 assert_eq!(lexer.next(), Some(Ok(Token::Comma)));
1118 assert_eq!(lexer.next(), Some(Ok(Token::TyString)));
1119 assert_eq!(lexer.next(), Some(Ok(Token::RParen)));
1120 assert_eq!(lexer.next(), Some(Ok(Token::Arrow)));
1121 assert_eq!(lexer.next(), Some(Ok(Token::TyBool)));
1122 assert_eq!(lexer.next(), None);
1123 }
1124
1125 #[test]
1126 fn fn_is_type_keyword() {
1127 assert!(Token::TyFn.is_type_keyword());
1128 }
1129
1130 #[test]
1131 fn pipe_display() {
1132 assert_eq!(format!("{}", Token::Pipe), "|");
1133 assert_eq!(format!("{}", Token::TyFn), "Fn");
1134 }
1135
1136 #[test]
1141 fn lex_tool_keyword() {
1142 let mut lexer = Token::lexer("tool Http { fn get(url: String) -> String }");
1143 assert_eq!(lexer.next(), Some(Ok(Token::KwTool)));
1144 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
1146 assert_eq!(lexer.next(), Some(Ok(Token::KwFn)));
1147 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::LParen)));
1149 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::Colon)));
1151 assert_eq!(lexer.next(), Some(Ok(Token::TyString)));
1152 assert_eq!(lexer.next(), Some(Ok(Token::RParen)));
1153 assert_eq!(lexer.next(), Some(Ok(Token::Arrow)));
1154 assert_eq!(lexer.next(), Some(Ok(Token::TyString)));
1155 assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
1156 assert_eq!(lexer.next(), None);
1157 }
1158
1159 #[test]
1160 fn tool_is_keyword() {
1161 assert!(Token::KwTool.is_keyword());
1162 }
1163
1164 #[test]
1165 fn lex_agent_use_tool() {
1166 let mut lexer = Token::lexer("agent Fetcher { use Http }");
1167 assert_eq!(lexer.next(), Some(Ok(Token::KwAgent)));
1168 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::LBrace)));
1170 assert_eq!(lexer.next(), Some(Ok(Token::KwUse)));
1171 assert_eq!(lexer.next(), Some(Ok(Token::Ident))); assert_eq!(lexer.next(), Some(Ok(Token::RBrace)));
1173 assert_eq!(lexer.next(), None);
1174 }
1175}