1#[repr(u8)]
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7#[non_exhaustive]
8pub enum TokenKind {
9 FloatLiteral,
14
15 FloatLiteralSimple,
17
18 FloatLiteralLeadingDot,
20
21 HexIntLiteral,
23
24 BinIntLiteral,
26
27 OctIntLiteralNew,
29
30 OctIntLiteral,
32
33 IntLiteral,
35
36 SingleQuotedString,
38
39 DoubleQuotedString,
41
42 BacktickString,
44
45 Variable,
50
51 Dollar,
53
54 Identifier,
60
61 Plus,
66 Minus,
68 Star,
70 Slash,
72 Percent,
74 StarStar,
76 Dot,
78
79 Equals,
85 PlusEquals,
87 MinusEquals,
89 StarEquals,
91 SlashEquals,
93 PercentEquals,
95 StarStarEquals,
97 DotEquals,
99 AmpersandEquals,
101 PipeEquals,
103 CaretEquals,
105 ShiftLeftEquals,
107 ShiftRightEquals,
109 CoalesceEquals,
111
112 EqualsEquals,
117 BangEquals,
119 EqualsEqualsEquals,
121 BangEqualsEquals,
123 LessThan,
125 GreaterThan,
127 LessThanEquals,
129 GreaterThanEquals,
131 Spaceship,
133
134 AmpersandAmpersand,
139 PipePipe,
141 Bang,
143
144 Ampersand,
146 Pipe,
148 Caret,
150 Tilde,
152 ShiftLeft,
154 ShiftRight,
156
157 PlusPlus,
162 MinusMinus,
164
165 Question,
170 QuestionQuestion,
172 Colon,
174
175 FatArrow,
177
178 PipeArrow,
180
181 LeftParen,
186 RightParen,
188 LeftBracket,
190 RightBracket,
192 LeftBrace,
194 RightBrace,
196 Semicolon,
198 Comma,
200
201 DoubleColon,
203
204 Arrow,
206
207 NullsafeArrow,
209
210 Backslash,
212
213 At,
215
216 HashBracket,
218
219 Ellipsis,
221
222 If,
227 Else,
229 ElseIf,
231 While,
233 Do,
235 For,
237 Foreach,
239 As,
241 Function,
243 Return,
245 Echo,
247 Print,
249 True,
251 False,
253 Null,
255 And,
257 Or,
259 Xor,
261 Break,
263 Continue,
265 Switch,
267 Case,
269 Default,
271 EndIf,
273 EndWhile,
275 EndFor,
277 EndForeach,
279 Throw,
281 Try,
283 Catch,
285 Finally,
287 Instanceof,
289 Array,
291 List,
293 Goto,
295 Declare,
297 Unset,
299 Global,
301 EndDeclare,
303 EndSwitch,
305 Isset,
307 Empty,
309 Include,
311 IncludeOnce,
313 Require,
315 RequireOnce,
317 Eval,
319 Exit,
321 Die,
323 Clone,
325
326 New,
329 Class,
331 Abstract,
333 Final,
335 Interface,
337 Trait,
339 Extends,
341 Implements,
343 Public,
345 Protected,
347 Private,
349 Static,
351 Const,
353 Fn_,
355 Match_,
357 Namespace,
359 Use,
361 Readonly,
363 Enum_,
365 Yield_,
367 From,
369 Self_,
371 Parent_,
373
374 MagicClass,
379 MagicDir,
381 MagicFile,
383 MagicFunction,
385 MagicLine,
387 MagicMethod,
389 MagicNamespace,
391 MagicTrait,
393 MagicProperty,
395 HaltCompiler,
397
398 OpenTag,
403
404 CloseTag,
406
407 InlineHtml,
409
410 Heredoc,
415 Nowdoc,
417
418 InvalidNumericLiteral,
424
425 LineComment,
430 HashComment,
432 BlockComment,
434 DocComment,
436
437 Eof,
442}
443
444impl TokenKind {
445 #[inline]
447 pub fn is_comment(self) -> bool {
448 matches!(
449 self,
450 TokenKind::LineComment
451 | TokenKind::HashComment
452 | TokenKind::BlockComment
453 | TokenKind::DocComment
454 )
455 }
456}
457
458impl TokenKind {
459 #[inline(always)]
461 pub fn is_assignment_op(self) -> bool {
462 (self as u8).wrapping_sub(TokenKind::Equals as u8)
465 <= (TokenKind::CoalesceEquals as u8 - TokenKind::Equals as u8)
466 }
467}
468
469pub fn resolve_keyword(text: &str) -> Option<TokenKind> {
472 let t = text;
475 match text.len() {
476 2 => {
477 if t.eq_ignore_ascii_case("if") {
478 return Some(TokenKind::If);
479 }
480 if t.eq_ignore_ascii_case("do") {
481 return Some(TokenKind::Do);
482 }
483 if t.eq_ignore_ascii_case("or") {
484 return Some(TokenKind::Or);
485 }
486 if t.eq_ignore_ascii_case("as") {
487 return Some(TokenKind::As);
488 }
489 if t.eq_ignore_ascii_case("fn") {
490 return Some(TokenKind::Fn_);
491 }
492 }
493 3 => {
494 if t.eq_ignore_ascii_case("for") {
495 return Some(TokenKind::For);
496 }
497 if t.eq_ignore_ascii_case("xor") {
498 return Some(TokenKind::Xor);
499 }
500 if t.eq_ignore_ascii_case("and") {
501 return Some(TokenKind::And);
502 }
503 if t.eq_ignore_ascii_case("new") {
504 return Some(TokenKind::New);
505 }
506 if t.eq_ignore_ascii_case("use") {
507 return Some(TokenKind::Use);
508 }
509 if t.eq_ignore_ascii_case("try") {
510 return Some(TokenKind::Try);
511 }
512 if t.eq_ignore_ascii_case("die") {
513 return Some(TokenKind::Die);
514 }
515 }
516 4 => {
517 if t.eq_ignore_ascii_case("else") {
518 return Some(TokenKind::Else);
519 }
520 if t.eq_ignore_ascii_case("echo") {
521 return Some(TokenKind::Echo);
522 }
523 if t.eq_ignore_ascii_case("true") {
524 return Some(TokenKind::True);
525 }
526 if t.eq_ignore_ascii_case("null") {
527 return Some(TokenKind::Null);
528 }
529 if t.eq_ignore_ascii_case("list") {
530 return Some(TokenKind::List);
531 }
532 if t.eq_ignore_ascii_case("goto") {
533 return Some(TokenKind::Goto);
534 }
535 if t.eq_ignore_ascii_case("case") {
536 return Some(TokenKind::Case);
537 }
538 if t.eq_ignore_ascii_case("self") {
539 return Some(TokenKind::Self_);
540 }
541 if t.eq_ignore_ascii_case("from") {
542 return Some(TokenKind::From);
543 }
544 if t.eq_ignore_ascii_case("enum") {
545 return Some(TokenKind::Enum_);
546 }
547 if t.eq_ignore_ascii_case("eval") {
548 return Some(TokenKind::Eval);
549 }
550 if t.eq_ignore_ascii_case("exit") {
551 return Some(TokenKind::Exit);
552 }
553 }
554 5 => {
555 if t.eq_ignore_ascii_case("while") {
556 return Some(TokenKind::While);
557 }
558 if t.eq_ignore_ascii_case("false") {
559 return Some(TokenKind::False);
560 }
561 if t.eq_ignore_ascii_case("array") {
562 return Some(TokenKind::Array);
563 }
564 if t.eq_ignore_ascii_case("unset") {
565 return Some(TokenKind::Unset);
566 }
567 if t.eq_ignore_ascii_case("isset") {
568 return Some(TokenKind::Isset);
569 }
570 if t.eq_ignore_ascii_case("empty") {
571 return Some(TokenKind::Empty);
572 }
573 if t.eq_ignore_ascii_case("print") {
574 return Some(TokenKind::Print);
575 }
576 if t.eq_ignore_ascii_case("throw") {
577 return Some(TokenKind::Throw);
578 }
579 if t.eq_ignore_ascii_case("catch") {
580 return Some(TokenKind::Catch);
581 }
582 if t.eq_ignore_ascii_case("break") {
583 return Some(TokenKind::Break);
584 }
585 if t.eq_ignore_ascii_case("yield") {
586 return Some(TokenKind::Yield_);
587 }
588 if t.eq_ignore_ascii_case("class") {
589 return Some(TokenKind::Class);
590 }
591 if t.eq_ignore_ascii_case("const") {
592 return Some(TokenKind::Const);
593 }
594 if t.eq_ignore_ascii_case("final") {
595 return Some(TokenKind::Final);
596 }
597 if t.eq_ignore_ascii_case("match") {
598 return Some(TokenKind::Match_);
599 }
600 if t.eq_ignore_ascii_case("trait") {
601 return Some(TokenKind::Trait);
602 }
603 if t.eq_ignore_ascii_case("clone") {
604 return Some(TokenKind::Clone);
605 }
606 if t.eq_ignore_ascii_case("endif") {
607 return Some(TokenKind::EndIf);
608 }
609 }
610 6 => {
611 if t.eq_ignore_ascii_case("elseif") {
612 return Some(TokenKind::ElseIf);
613 }
614 if t.eq_ignore_ascii_case("return") {
615 return Some(TokenKind::Return);
616 }
617 if t.eq_ignore_ascii_case("switch") {
618 return Some(TokenKind::Switch);
619 }
620 if t.eq_ignore_ascii_case("global") {
621 return Some(TokenKind::Global);
622 }
623 if t.eq_ignore_ascii_case("static") {
624 return Some(TokenKind::Static);
625 }
626 if t.eq_ignore_ascii_case("public") {
627 return Some(TokenKind::Public);
628 }
629 if t.eq_ignore_ascii_case("parent") {
630 return Some(TokenKind::Parent_);
631 }
632 if t.eq_ignore_ascii_case("endfor") {
633 return Some(TokenKind::EndFor);
634 }
635 }
636 7 => {
637 if t.eq_ignore_ascii_case("foreach") {
638 return Some(TokenKind::Foreach);
639 }
640 if t.eq_ignore_ascii_case("default") {
641 return Some(TokenKind::Default);
642 }
643 if t.eq_ignore_ascii_case("finally") {
644 return Some(TokenKind::Finally);
645 }
646 if t.eq_ignore_ascii_case("include") {
647 return Some(TokenKind::Include);
648 }
649 if t.eq_ignore_ascii_case("declare") {
650 return Some(TokenKind::Declare);
651 }
652 if t.eq_ignore_ascii_case("extends") {
653 return Some(TokenKind::Extends);
654 }
655 if t.eq_ignore_ascii_case("require") {
656 return Some(TokenKind::Require);
657 }
658 if t.eq_ignore_ascii_case("private") {
659 return Some(TokenKind::Private);
660 }
661 if t.eq_ignore_ascii_case("__dir__") {
662 return Some(TokenKind::MagicDir);
663 }
664 }
665 8 => {
666 if t.eq_ignore_ascii_case("function") {
667 return Some(TokenKind::Function);
668 }
669 if t.eq_ignore_ascii_case("abstract") {
670 return Some(TokenKind::Abstract);
671 }
672 if t.eq_ignore_ascii_case("readonly") {
673 return Some(TokenKind::Readonly);
674 }
675 if t.eq_ignore_ascii_case("continue") {
676 return Some(TokenKind::Continue);
677 }
678 if t.eq_ignore_ascii_case("endwhile") {
679 return Some(TokenKind::EndWhile);
680 }
681 if t.eq_ignore_ascii_case("__file__") {
682 return Some(TokenKind::MagicFile);
683 }
684 if t.eq_ignore_ascii_case("__line__") {
685 return Some(TokenKind::MagicLine);
686 }
687 }
688 9 => {
689 if t.eq_ignore_ascii_case("namespace") {
690 return Some(TokenKind::Namespace);
691 }
692 if t.eq_ignore_ascii_case("interface") {
693 return Some(TokenKind::Interface);
694 }
695 if t.eq_ignore_ascii_case("protected") {
696 return Some(TokenKind::Protected);
697 }
698 if t.eq_ignore_ascii_case("endswitch") {
699 return Some(TokenKind::EndSwitch);
700 }
701 if t.eq_ignore_ascii_case("__class__") {
702 return Some(TokenKind::MagicClass);
703 }
704 if t.eq_ignore_ascii_case("__trait__") {
705 return Some(TokenKind::MagicTrait);
706 }
707 }
708 10 => {
709 if t.eq_ignore_ascii_case("implements") {
710 return Some(TokenKind::Implements);
711 }
712 if t.eq_ignore_ascii_case("instanceof") {
713 return Some(TokenKind::Instanceof);
714 }
715 if t.eq_ignore_ascii_case("endforeach") {
716 return Some(TokenKind::EndForeach);
717 }
718 if t.eq_ignore_ascii_case("enddeclare") {
719 return Some(TokenKind::EndDeclare);
720 }
721 if t.eq_ignore_ascii_case("__method__") {
722 return Some(TokenKind::MagicMethod);
723 }
724 }
725 12 => {
726 if t.eq_ignore_ascii_case("include_once") {
727 return Some(TokenKind::IncludeOnce);
728 }
729 if t.eq_ignore_ascii_case("require_once") {
730 return Some(TokenKind::RequireOnce);
731 }
732 if t.eq_ignore_ascii_case("__function__") {
733 return Some(TokenKind::MagicFunction);
734 }
735 if t.eq_ignore_ascii_case("__property__") {
736 return Some(TokenKind::MagicProperty);
737 }
738 }
739 13 if t.eq_ignore_ascii_case("__namespace__") => {
740 return Some(TokenKind::MagicNamespace);
741 }
742 15 if t.eq_ignore_ascii_case("__halt_compiler") => {
743 return Some(TokenKind::HaltCompiler);
744 }
745 _ => {}
746 }
747 None
748}
749
750impl TokenKind {
751 pub fn description(self) -> &'static str {
754 match self {
755 TokenKind::IntLiteral => "integer",
756 TokenKind::HexIntLiteral => "hex integer",
757 TokenKind::BinIntLiteral => "binary integer",
758 TokenKind::OctIntLiteral | TokenKind::OctIntLiteralNew => "octal integer",
759 TokenKind::FloatLiteral
760 | TokenKind::FloatLiteralSimple
761 | TokenKind::FloatLiteralLeadingDot => "float",
762 TokenKind::SingleQuotedString | TokenKind::DoubleQuotedString => "string",
763 TokenKind::BacktickString => "backtick string",
764 TokenKind::Variable => "variable",
765 TokenKind::Dollar => "'$'",
766 TokenKind::Identifier => "identifier",
767 TokenKind::Plus => "'+'",
768 TokenKind::Minus => "'-'",
769 TokenKind::Star => "'*'",
770 TokenKind::Slash => "'/'",
771 TokenKind::Percent => "'%'",
772 TokenKind::StarStar => "'**'",
773 TokenKind::Dot => "'.'",
774 TokenKind::Equals => "'='",
775 TokenKind::PlusEquals => "'+='",
776 TokenKind::MinusEquals => "'-='",
777 TokenKind::StarEquals => "'*='",
778 TokenKind::SlashEquals => "'/='",
779 TokenKind::PercentEquals => "'%='",
780 TokenKind::StarStarEquals => "'**='",
781 TokenKind::DotEquals => "'.='",
782 TokenKind::AmpersandEquals => "'&='",
783 TokenKind::PipeEquals => "'|='",
784 TokenKind::CaretEquals => "'^='",
785 TokenKind::ShiftLeftEquals => "'<<='",
786 TokenKind::ShiftRightEquals => "'>>='",
787 TokenKind::CoalesceEquals => "'??='",
788 TokenKind::EqualsEquals => "'=='",
789 TokenKind::BangEquals => "'!='",
790 TokenKind::EqualsEqualsEquals => "'==='",
791 TokenKind::BangEqualsEquals => "'!=='",
792 TokenKind::LessThan => "'<'",
793 TokenKind::GreaterThan => "'>'",
794 TokenKind::LessThanEquals => "'<='",
795 TokenKind::GreaterThanEquals => "'>='",
796 TokenKind::Spaceship => "'<=>'",
797 TokenKind::AmpersandAmpersand => "'&&'",
798 TokenKind::PipePipe => "'||'",
799 TokenKind::Bang => "'!'",
800 TokenKind::Ampersand => "'&'",
801 TokenKind::Pipe => "'|'",
802 TokenKind::Caret => "'^'",
803 TokenKind::Tilde => "'~'",
804 TokenKind::ShiftLeft => "'<<'",
805 TokenKind::ShiftRight => "'>>'",
806 TokenKind::PlusPlus => "'++'",
807 TokenKind::MinusMinus => "'--'",
808 TokenKind::Question => "'?'",
809 TokenKind::QuestionQuestion => "'??'",
810 TokenKind::Colon => "':'",
811 TokenKind::FatArrow => "'=>'",
812 TokenKind::PipeArrow => "'|>'",
813 TokenKind::LeftParen => "'('",
814 TokenKind::RightParen => "')'",
815 TokenKind::LeftBracket => "'['",
816 TokenKind::RightBracket => "']'",
817 TokenKind::LeftBrace => "'{'",
818 TokenKind::RightBrace => "'}'",
819 TokenKind::Semicolon => "';'",
820 TokenKind::Comma => "','",
821 TokenKind::DoubleColon => "'::'",
822 TokenKind::Arrow => "'->'",
823 TokenKind::NullsafeArrow => "'?->'",
824 TokenKind::Backslash => "'\\'",
825 TokenKind::At => "'@'",
826 TokenKind::HashBracket => "'#['",
827 TokenKind::Ellipsis => "'...'",
828 TokenKind::If => "'if'",
829 TokenKind::Else => "'else'",
830 TokenKind::ElseIf => "'elseif'",
831 TokenKind::While => "'while'",
832 TokenKind::Do => "'do'",
833 TokenKind::For => "'for'",
834 TokenKind::Foreach => "'foreach'",
835 TokenKind::As => "'as'",
836 TokenKind::Function => "'function'",
837 TokenKind::Return => "'return'",
838 TokenKind::Echo => "'echo'",
839 TokenKind::Print => "'print'",
840 TokenKind::True => "'true'",
841 TokenKind::False => "'false'",
842 TokenKind::Null => "'null'",
843 TokenKind::And => "'and'",
844 TokenKind::Or => "'or'",
845 TokenKind::Xor => "'xor'",
846 TokenKind::Break => "'break'",
847 TokenKind::Continue => "'continue'",
848 TokenKind::Switch => "'switch'",
849 TokenKind::Case => "'case'",
850 TokenKind::Default => "'default'",
851 TokenKind::EndIf => "'endif'",
852 TokenKind::EndWhile => "'endwhile'",
853 TokenKind::EndFor => "'endfor'",
854 TokenKind::EndForeach => "'endforeach'",
855 TokenKind::Throw => "'throw'",
856 TokenKind::Try => "'try'",
857 TokenKind::Catch => "'catch'",
858 TokenKind::Finally => "'finally'",
859 TokenKind::Instanceof => "'instanceof'",
860 TokenKind::Array => "'array'",
861 TokenKind::List => "'list'",
862 TokenKind::Goto => "'goto'",
863 TokenKind::Declare => "'declare'",
864 TokenKind::Unset => "'unset'",
865 TokenKind::Global => "'global'",
866 TokenKind::EndDeclare => "'enddeclare'",
867 TokenKind::EndSwitch => "'endswitch'",
868 TokenKind::Isset => "'isset'",
869 TokenKind::Empty => "'empty'",
870 TokenKind::Include => "'include'",
871 TokenKind::IncludeOnce => "'include_once'",
872 TokenKind::Require => "'require'",
873 TokenKind::RequireOnce => "'require_once'",
874 TokenKind::Eval => "'eval'",
875 TokenKind::Exit => "'exit'",
876 TokenKind::Die => "'die'",
877 TokenKind::Clone => "'clone'",
878 TokenKind::New => "'new'",
879 TokenKind::Class => "'class'",
880 TokenKind::Abstract => "'abstract'",
881 TokenKind::Final => "'final'",
882 TokenKind::Interface => "'interface'",
883 TokenKind::Trait => "'trait'",
884 TokenKind::Extends => "'extends'",
885 TokenKind::Implements => "'implements'",
886 TokenKind::Public => "'public'",
887 TokenKind::Protected => "'protected'",
888 TokenKind::Private => "'private'",
889 TokenKind::Static => "'static'",
890 TokenKind::Const => "'const'",
891 TokenKind::Fn_ => "'fn'",
892 TokenKind::Match_ => "'match'",
893 TokenKind::Namespace => "'namespace'",
894 TokenKind::Use => "'use'",
895 TokenKind::Readonly => "'readonly'",
896 TokenKind::Enum_ => "'enum'",
897 TokenKind::Yield_ => "'yield'",
898 TokenKind::From => "'from'",
899 TokenKind::Self_ => "'self'",
900 TokenKind::Parent_ => "'parent'",
901 TokenKind::MagicClass => "'__CLASS__'",
902 TokenKind::MagicDir => "'__DIR__'",
903 TokenKind::MagicFile => "'__FILE__'",
904 TokenKind::MagicFunction => "'__FUNCTION__'",
905 TokenKind::MagicLine => "'__LINE__'",
906 TokenKind::MagicMethod => "'__METHOD__'",
907 TokenKind::MagicNamespace => "'__NAMESPACE__'",
908 TokenKind::MagicTrait => "'__TRAIT__'",
909 TokenKind::MagicProperty => "'__PROPERTY__'",
910 TokenKind::HaltCompiler => "'__halt_compiler'",
911 TokenKind::OpenTag => "'<?php'",
912 TokenKind::CloseTag => "'?>'",
913 TokenKind::InlineHtml => "inline HTML",
914 TokenKind::Heredoc => "heredoc",
915 TokenKind::Nowdoc => "nowdoc",
916 TokenKind::InvalidNumericLiteral => "invalid numeric literal",
917 TokenKind::LineComment => "line comment",
918 TokenKind::HashComment => "hash comment",
919 TokenKind::BlockComment => "block comment",
920 TokenKind::DocComment => "doc comment",
921 TokenKind::Eof => "end of file",
922 }
923 }
924}
925
926impl std::fmt::Display for TokenKind {
927 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
928 f.write_str(self.description())
929 }
930}
931
932#[cfg(test)]
933mod tests {
934 use super::*;
935
936 #[test]
937 fn test_resolve_keyword() {
938 assert_eq!(resolve_keyword("if"), Some(TokenKind::If));
939 assert_eq!(resolve_keyword("IF"), Some(TokenKind::If));
940 assert_eq!(resolve_keyword("If"), Some(TokenKind::If));
941 assert_eq!(resolve_keyword("function"), Some(TokenKind::Function));
942 assert_eq!(resolve_keyword("myFunc"), None);
943 assert_eq!(resolve_keyword("true"), Some(TokenKind::True));
944 assert_eq!(resolve_keyword("TRUE"), Some(TokenKind::True));
945 assert_eq!(resolve_keyword("null"), Some(TokenKind::Null));
946 }
947
948 #[test]
949 fn test_is_assignment_op() {
950 assert!(TokenKind::Equals.is_assignment_op());
951 assert!(TokenKind::PlusEquals.is_assignment_op());
952 assert!(TokenKind::DotEquals.is_assignment_op());
953 assert!(!TokenKind::Plus.is_assignment_op());
954 assert!(!TokenKind::EqualsEquals.is_assignment_op());
955 }
956}