mago_token/
lib.rs

1use serde::Deserialize;
2use serde::Serialize;
3use strum::Display;
4
5use mago_interner::StringIdentifier;
6use mago_span::Span;
7
8#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
9#[serde(tag = "type", content = "value")]
10#[repr(C)]
11pub enum DocumentKind {
12    Heredoc,
13    Nowdoc,
14}
15
16#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
17#[serde(tag = "type", content = "value")]
18#[repr(C)]
19pub enum Associativity {
20    NonAssociative,
21    Left,
22    Right,
23}
24
25#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
26#[serde(tag = "type", content = "value")]
27#[repr(C)]
28pub enum Precedence {
29    Lowest,
30    LowLogicalOr,
31    LowLogicalXor,
32    LowLogicalAnd,
33    Print,
34    Yield,
35    YieldFrom,
36    IncDec,
37    KeyOr,
38    KeyXor,
39    KeyAnd,
40    Assignment,
41    ElvisOrConditional,
42    NullCoalesce,
43    Or,
44    And,
45    BitwiseOr,
46    BitwiseXor,
47    BitwiseAnd,
48    Equality,
49    Comparison,
50    Concat,
51    BitShift,
52    AddSub,
53    MulDivMod,
54    Bang,
55    Instanceof,
56    Prefix,
57    Pow,
58    Clone,
59    CallDim,
60    New,
61    ArrayDim,
62    ObjectAccess,
63}
64
65pub trait GetPrecedence {
66    fn precedence(&self) -> Precedence;
67}
68
69#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, Display)]
70#[serde(tag = "type", content = "value")]
71#[repr(C)]
72pub enum TokenKind {
73    Whitespace,                  // ` `
74    Eval,                        // `eval`
75    Die,                         // `die`
76    Self_,                       // `self`
77    Parent,                      // `parent`
78    Backtick,                    // `` ` ``
79    DocumentStart(DocumentKind), // `<<<abc`, or `<<<'abc'`
80    DocumentEnd,                 // `abc`
81    From,                        // `from`
82    Print,                       // `print`
83    Dollar,                      // `$`
84    HaltCompiler,                // `__halt_compiler`
85    Readonly,                    // `readonly`
86    Global,                      // `global`
87    Abstract,                    // `abstract`
88    Ampersand,                   // `&`
89    AmpersandEqual,              // `&=`
90    AmpersandAmpersand,          // `&&`
91    AmpersandAmpersandEqual,     // `&&=`
92    Array,                       // `array`
93    ArrayCast,                   // `(array)`
94    MinusGreaterThan,            // `->`
95    QuestionMinusGreaterThan,    // `?->`
96    At,                          // `@`
97    As,                          // `as`
98    Asterisk,                    // `*`
99    HashLeftBracket,             // `#[`
100    Bang,                        // `!`
101    BangEqual,                   // `!=`
102    LessThanGreaterThan,         // `<>`
103    BangEqualEqual,              // `!==`
104    LessThanEqualGreaterThan,    // `<=>`
105    BoolCast,                    // `(bool)`
106    BooleanCast,                 // `(boolean)`
107    And,                         // `and`
108    Or,                          // `or`
109    Break,                       // `break`
110    Callable,                    // `callable`
111    Caret,                       // `^`
112    CaretEqual,                  // `^=`
113    Case,                        // `case`
114    Catch,                       // `catch`
115    Class,                       // `class`
116    ClassConstant,               // `__CLASS__`
117    TraitConstant,               // `__TRAIT__`
118    FunctionConstant,            // `__FUNCTION__`
119    MethodConstant,              // `__METHOD__`
120    LineConstant,                // `__LINE__`
121    FileConstant,                // `__FILE__`
122    Clone,                       // `clone`
123    MinusEqual,                  // `-=`
124    CloseTag,                    // `?>`
125    QuestionQuestion,            // `??`
126    QuestionQuestionEqual,       // `??=`
127    AsteriskEqual,               // `*=`
128    Colon,                       // `:`
129    Comma,                       // `,`
130    SingleLineComment,           // `// comment`
131    HashComment,                 // `# comment`
132    MultiLineComment,            // `/* comment */`
133    DocBlockComment,             // `/** comment */`
134    Const,                       // `const`
135    PartialLiteralString,        // `"string` or `'string`, missing closing quote
136    LiteralString,               // `"string"` or `'string'`
137    Continue,                    // `continue`
138    Declare,                     // `declare`
139    MinusMinus,                  // `--`
140    Default,                     // `default`
141    DirConstant,                 // `__DIR__`
142    SlashEqual,                  // `/=`
143    Do,                          // `do`
144    DollarLeftBrace,             // `${`
145    Dot,                         // `.`
146    DotEqual,                    // `.=`
147    EqualGreaterThan,            // `=>`
148    DoubleCast,                  // `(double)`
149    RealCast,                    // `(real)`
150    FloatCast,                   // `(float)`
151    ColonColon,                  // `::`
152    EqualEqual,                  // `==`
153    DoubleQuote,                 // `"`
154    Else,                        // `else`
155    Echo,                        // `echo`
156    DotDotDot,                   // `...`
157    ElseIf,                      // `elseif`
158    Empty,                       // `empty`
159    EndDeclare,                  // `enddeclare`
160    EndFor,                      // `endfor`
161    EndForeach,                  // `endforeach`
162    EndIf,                       // `endif`
163    EndSwitch,                   // `endswitch`
164    EndWhile,                    // `endwhile`
165    Enum,                        // `enum`
166    Equal,                       // `=`
167    Extends,                     // `extends`
168    False,                       // `false`
169    Final,                       // `final`
170    Finally,                     // `finally`
171    LiteralFloat,                // `1.0`
172    Fn,                          // `fn`
173    For,                         // `for`
174    Foreach,                     // `foreach`
175    FullyQualifiedIdentifier,    // `\Namespace\Class`
176    Function,                    // `function`
177    Goto,                        // `goto`
178    GreaterThan,                 // `>`
179    GreaterThanEqual,            // `>=`
180    Identifier,                  // `name`
181    If,                          // `if`
182    Implements,                  // `implements`
183    Include,                     // `include`
184    IncludeOnce,                 // `include_once`
185    PlusPlus,                    // `++`
186    InlineText,                  // inline text outside of PHP tags, also referred to as "HTML"
187    InlineShebang,               // `#!...`
188    Instanceof,                  // `instanceof`
189    Insteadof,                   // `insteadof`
190    Exit,                        // `exit`
191    Unset,                       // `unset`
192    Isset,                       // `isset`
193    List,                        // `list`
194    LiteralInteger,              // `1`
195    IntCast,                     // `(int)`
196    IntegerCast,                 // `(integer)`
197    Interface,                   // `interface`
198    LeftBrace,                   // `{`
199    LeftBracket,                 // `[`
200    LeftParenthesis,             // `(`
201    LeftShift,                   // `<<`
202    LeftShiftEqual,              // `<<=`
203    RightShift,                  // `>>`
204    RightShiftEqual,             // `>>=`
205    LessThan,                    // `<`
206    LessThanEqual,               // `<=`
207    Match,                       // `match`
208    Minus,                       // `-`
209    Namespace,                   // `namespace`
210    NamespaceSeparator,          // `\`
211    NamespaceConstant,           // `__NAMESPACE__`
212    New,                         // `new`
213    Null,                        // `null`
214    ObjectCast,                  // `(object)`
215    UnsetCast,                   // `(unset)`
216    OpenTag,                     // `<?php`
217    EchoTag,                     // `<?=`
218    ShortOpenTag,                // `<?`
219    Percent,                     // `%`
220    PercentEqual,                // `%=`
221    Pipe,                        // `|`
222    PipeEqual,                   // `|=`
223    Plus,                        // `+`
224    PlusEqual,                   // `+=`
225    AsteriskAsterisk,            // `**`
226    AsteriskAsteriskEqual,       // `**=`
227    Private,                     // `private`
228    PrivateSet,                  // `private(set)`
229    Protected,                   // `protected`
230    ProtectedSet,                // `protected(set)`
231    Public,                      // `public`
232    PublicSet,                   // `public(set)`
233    QualifiedIdentifier,         // `Namespace\Class`
234    Question,                    // `?`
235    QuestionColon,               // `?:`
236    Require,                     // `require`
237    RequireOnce,                 // `require_once`
238    Return,                      // `return`
239    RightBrace,                  // `}`
240    RightBracket,                // `]`
241    RightParenthesis,            // `)`
242    Semicolon,                   // `;`
243    Slash,                       // `/`
244    Static,                      // `static`
245    StringCast,                  // `(string)`
246    BinaryCast,                  // `(binary)`
247    StringPart,                  // `string` inside a double-quoted string, or a document string
248    Switch,                      // `switch`
249    Throw,                       // `throw`
250    Trait,                       // `trait`
251    EqualEqualEqual,             // `===`
252    True,                        // `true`
253    Try,                         // `try`
254    Use,                         // `use`
255    Var,                         // `var`
256    Variable,                    // `$name`
257    Yield,                       // `yield`
258    While,                       // `while`
259    Tilde,                       // `~`
260    PipePipe,                    // `||`
261    Xor,                         // `xor`
262}
263
264#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
265#[repr(C)]
266pub struct Token {
267    pub kind: TokenKind,
268    pub value: StringIdentifier,
269    pub span: Span,
270}
271
272impl Precedence {
273    #[inline(always)]
274    pub fn infix(kind: &TokenKind) -> Precedence {
275        match kind {
276            T!["**"] => Precedence::Pow,
277            T!["instanceof"] => Precedence::Instanceof,
278            T!["*" | "/" | "%"] => Precedence::MulDivMod,
279            T!["+" | "-"] => Precedence::AddSub,
280            T!["<<"] | T![">>"] => Precedence::BitShift,
281            T!["."] => Precedence::Concat,
282            T!["<" | "<=" | ">" | ">="] => Precedence::Comparison,
283            T!["==" | "!=" | "===" | "!==" | "<>" | "<=>"] => Precedence::Equality,
284            T!["&"] => Precedence::BitwiseAnd,
285            T!["^"] => Precedence::BitwiseXor,
286            T!["|"] => Precedence::BitwiseOr,
287            T!["&&"] => Precedence::And,
288            T!["||"] => Precedence::Or,
289            T!["??"] => Precedence::NullCoalesce,
290            T!["?" | "?:"] => Precedence::ElvisOrConditional,
291            T!["="
292                | "+="
293                | "-="
294                | "*="
295                | "**="
296                | "/="
297                | ".="
298                | "&&="
299                | "??="
300                | "%="
301                | "&="
302                | "|="
303                | "^="
304                | "<<="
305                | ">>="] => Precedence::Assignment,
306            T!["yield"] => Precedence::Yield,
307            T!["and"] => Precedence::KeyAnd,
308            T!["or"] => Precedence::KeyOr,
309            T!["xor"] => Precedence::KeyXor,
310            _ => Precedence::Lowest,
311        }
312    }
313
314    #[inline(always)]
315    pub fn postfix(kind: &TokenKind) -> Self {
316        match kind {
317            T!["++" | "--"] => Self::Prefix,
318            T!["("] => Self::CallDim,
319            T!["["] => Self::ArrayDim,
320            T!["->" | "?->" | "::"] => Self::ObjectAccess,
321            _ => Self::Lowest,
322        }
323    }
324
325    #[inline(always)]
326    pub fn associativity(&self) -> Option<Associativity> {
327        Some(match self {
328            Self::Instanceof
329            | Self::MulDivMod
330            | Self::AddSub
331            | Self::BitShift
332            | Self::Concat
333            | Self::BitwiseAnd
334            | Self::BitwiseOr
335            | Self::BitwiseXor
336            | Self::And
337            | Self::Or
338            | Self::KeyAnd
339            | Self::KeyOr
340            | Self::KeyXor => Associativity::Left,
341            Self::Pow | Self::NullCoalesce | Self::Assignment => Associativity::Right,
342            Self::ElvisOrConditional | Self::Equality | Self::Comparison => Associativity::NonAssociative,
343            _ => return None,
344        })
345    }
346}
347
348impl TokenKind {
349    #[inline(always)]
350    pub const fn is_keyword(&self) -> bool {
351        matches!(
352            self,
353            TokenKind::Eval
354                | TokenKind::Die
355                | TokenKind::Empty
356                | TokenKind::Isset
357                | TokenKind::Unset
358                | TokenKind::Exit
359                | TokenKind::EndDeclare
360                | TokenKind::EndSwitch
361                | TokenKind::EndWhile
362                | TokenKind::EndForeach
363                | TokenKind::EndFor
364                | TokenKind::EndIf
365                | TokenKind::From
366                | TokenKind::And
367                | TokenKind::Or
368                | TokenKind::Xor
369                | TokenKind::Print
370                | TokenKind::Readonly
371                | TokenKind::Global
372                | TokenKind::Match
373                | TokenKind::Abstract
374                | TokenKind::Array
375                | TokenKind::As
376                | TokenKind::Break
377                | TokenKind::Case
378                | TokenKind::Catch
379                | TokenKind::Class
380                | TokenKind::Clone
381                | TokenKind::Continue
382                | TokenKind::Const
383                | TokenKind::Declare
384                | TokenKind::Default
385                | TokenKind::Do
386                | TokenKind::Echo
387                | TokenKind::ElseIf
388                | TokenKind::Else
389                | TokenKind::Enum
390                | TokenKind::Extends
391                | TokenKind::False
392                | TokenKind::Finally
393                | TokenKind::Final
394                | TokenKind::Fn
395                | TokenKind::Foreach
396                | TokenKind::For
397                | TokenKind::Function
398                | TokenKind::Goto
399                | TokenKind::If
400                | TokenKind::IncludeOnce
401                | TokenKind::Include
402                | TokenKind::Implements
403                | TokenKind::Interface
404                | TokenKind::Instanceof
405                | TokenKind::Namespace
406                | TokenKind::New
407                | TokenKind::Null
408                | TokenKind::Private
409                | TokenKind::PrivateSet
410                | TokenKind::Protected
411                | TokenKind::Public
412                | TokenKind::RequireOnce
413                | TokenKind::Require
414                | TokenKind::Return
415                | TokenKind::Static
416                | TokenKind::Switch
417                | TokenKind::Throw
418                | TokenKind::Trait
419                | TokenKind::True
420                | TokenKind::Try
421                | TokenKind::Use
422                | TokenKind::Var
423                | TokenKind::Yield
424                | TokenKind::While
425                | TokenKind::Insteadof
426                | TokenKind::List
427                | TokenKind::Self_
428                | TokenKind::Parent
429                | TokenKind::DirConstant
430                | TokenKind::FileConstant
431                | TokenKind::LineConstant
432                | TokenKind::FunctionConstant
433                | TokenKind::ClassConstant
434                | TokenKind::MethodConstant
435                | TokenKind::TraitConstant
436                | TokenKind::NamespaceConstant
437                | TokenKind::HaltCompiler
438        )
439    }
440
441    #[inline(always)]
442    pub const fn is_infix(&self) -> bool {
443        matches!(
444            self,
445            T!["**"
446                | ">>="
447                | "<<="
448                | "^="
449                | "&="
450                | "|="
451                | "%="
452                | "**="
453                | "and"
454                | "or"
455                | "xor"
456                | "<=>"
457                | "<<"
458                | ">>"
459                | "&"
460                | "|"
461                | "^"
462                | "%"
463                | "instanceof"
464                | "*"
465                | "/"
466                | "+"
467                | "-"
468                | "."
469                | "<"
470                | ">"
471                | "<="
472                | ">="
473                | "=="
474                | "==="
475                | "!="
476                | "!=="
477                | "<>"
478                | "?"
479                | "?:"
480                | "&&"
481                | "||"
482                | "="
483                | "+="
484                | "-="
485                | ".="
486                | "??="
487                | "/="
488                | "*="
489                | "??"]
490        )
491    }
492
493    #[inline(always)]
494    pub const fn is_postfix(&self) -> bool {
495        matches!(self, T!["++" | "--" | "(" | "[" | "->" | "?->" | "::"])
496    }
497
498    #[inline(always)]
499    pub const fn is_visibility_modifier(&self) -> bool {
500        matches!(self, T!["public" | "protected" | "private" | "private(set)" | "protected(set)" | "public(set)"])
501    }
502
503    #[inline(always)]
504    pub const fn is_modifier(&self) -> bool {
505        matches!(
506            self,
507            T!["public"
508                | "protected"
509                | "private"
510                | "private(set)"
511                | "protected(set)"
512                | "public(set)"
513                | "static"
514                | "final"
515                | "abstract"
516                | "readonly"]
517        )
518    }
519
520    #[inline(always)]
521    pub const fn is_identifier_maybe_soft_reserved(&self) -> bool {
522        if let TokenKind::Identifier = self { true } else { self.is_soft_reserved_identifier() }
523    }
524
525    #[inline(always)]
526    pub const fn is_identifier_maybe_reserved(&self) -> bool {
527        if let TokenKind::Identifier = self { true } else { self.is_reserved_identifier() }
528    }
529
530    #[inline(always)]
531    pub const fn is_soft_reserved_identifier(&self) -> bool {
532        matches!(
533            self,
534            T!["parent" | "self" | "true" | "false" | "list" | "null" | "enum" | "from" | "readonly" | "match"]
535        )
536    }
537
538    #[inline(always)]
539    pub const fn is_reserved_identifier(&self) -> bool {
540        if self.is_soft_reserved_identifier() {
541            return true;
542        }
543
544        matches!(
545            self,
546            T!["static"
547                | "abstract"
548                | "final"
549                | "for"
550                | "private"
551                | "private(set)"
552                | "protected"
553                | "protected(set)"
554                | "public"
555                | "public(set)"
556                | "include"
557                | "include_once"
558                | "eval"
559                | "require"
560                | "require_once"
561                | "or"
562                | "xor"
563                | "and"
564                | "instanceof"
565                | "new"
566                | "clone"
567                | "exit"
568                | "die"
569                | "if"
570                | "elseif"
571                | "else"
572                | "endif"
573                | "echo"
574                | "do"
575                | "while"
576                | "endwhile"
577                | "endfor"
578                | "foreach"
579                | "endforeach"
580                | "declare"
581                | "enddeclare"
582                | "as"
583                | "try"
584                | "catch"
585                | "finally"
586                | "throw"
587                | "use"
588                | "insteadof"
589                | "global"
590                | "var"
591                | "unset"
592                | "isset"
593                | "empty"
594                | "continue"
595                | "goto"
596                | "function"
597                | "const"
598                | "return"
599                | "print"
600                | "yield"
601                | "list"
602                | "switch"
603                | "endswitch"
604                | "case"
605                | "default"
606                | "break"
607                | "array"
608                | "callable"
609                | "extends"
610                | "implements"
611                | "namespace"
612                | "trait"
613                | "interface"
614                | "class"
615                | "__CLASS__"
616                | "__TRAIT__"
617                | "__FUNCTION__"
618                | "__METHOD__"
619                | "__LINE__"
620                | "__FILE__"
621                | "__DIR__"
622                | "__NAMESPACE__"
623                | "__halt_compiler"
624                | "fn"
625                | "match"]
626        )
627    }
628
629    #[inline(always)]
630    pub const fn is_literal(&self) -> bool {
631        matches!(
632            self,
633            T!["true" | "false" | "null" | LiteralFloat | LiteralInteger | LiteralString | PartialLiteralString]
634        )
635    }
636
637    #[inline(always)]
638    pub const fn is_magic_constant(&self) -> bool {
639        matches!(
640            self,
641            T!["__CLASS__"
642                | "__DIR__"
643                | "__FILE__"
644                | "__FUNCTION__"
645                | "__LINE__"
646                | "__METHOD__"
647                | "__NAMESPACE__"
648                | "__TRAIT__"]
649        )
650    }
651
652    #[inline(always)]
653    pub const fn is_cast(&self) -> bool {
654        matches!(
655            self,
656            T!["(string)"
657                | "(binary)"
658                | "(int)"
659                | "(integer)"
660                | "(float)"
661                | "(double)"
662                | "(real)"
663                | "(bool)"
664                | "(boolean)"
665                | "(array)"
666                | "(object)"
667                | "(unset)"]
668        )
669    }
670
671    #[inline(always)]
672    pub const fn is_unary_prefix(&self) -> bool {
673        if self.is_cast() {
674            return true;
675        }
676
677        matches!(self, T!["@" | "!" | "~" | "-" | "+" | "++" | "--" | "&"])
678    }
679
680    #[inline(always)]
681    pub const fn is_trivia(&self) -> bool {
682        matches!(self, T![SingleLineComment | MultiLineComment | DocBlockComment | HashComment | Whitespace])
683    }
684
685    #[inline(always)]
686    pub const fn is_comment(&self) -> bool {
687        matches!(self, T![SingleLineComment | MultiLineComment | DocBlockComment | HashComment])
688    }
689
690    #[inline(always)]
691    pub const fn is_construct(&self) -> bool {
692        matches!(
693            self,
694            T!["isset"
695                | "empty"
696                | "eval"
697                | "include"
698                | "include_once"
699                | "require"
700                | "require_once"
701                | "print"
702                | "unset"
703                | "exit"
704                | "die"]
705        )
706    }
707}
708
709impl Token {
710    pub fn new(kind: TokenKind, value: StringIdentifier, span: Span) -> Self {
711        Self { kind, value, span }
712    }
713}
714
715impl std::fmt::Display for Token {
716    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
717        write!(f, "{:?} {}", self.kind, self.span)
718    }
719}
720
721#[macro_export]
722macro_rules! T {
723    ("eval") => {
724        $crate::TokenKind::Eval
725    };
726    ("die") => {
727        $crate::TokenKind::Die
728    };
729    ("self") => {
730        $crate::TokenKind::Self_
731    };
732    ("parent") => {
733        $crate::TokenKind::Parent
734    };
735    ("`") => {
736        $crate::TokenKind::Backtick
737    };
738    ("<<<") => {
739        $crate::TokenKind::DocumentStart(_)
740    };
741    (">>>") => {
742        $crate::TokenKind::DocumentEnd
743    };
744    ("from") => {
745        $crate::TokenKind::From
746    };
747    ("print") => {
748        $crate::TokenKind::Print
749    };
750    ("$") => {
751        $crate::TokenKind::Dollar
752    };
753    ("__halt_compiler") => {
754        $crate::TokenKind::HaltCompiler
755    };
756    ("readonly") => {
757        $crate::TokenKind::Readonly
758    };
759    ("global") => {
760        $crate::TokenKind::Global
761    };
762    ("abstract") => {
763        $crate::TokenKind::Abstract
764    };
765    ("&") => {
766        $crate::TokenKind::Ampersand
767    };
768    ("&=") => {
769        $crate::TokenKind::AmpersandEqual
770    };
771    ("&&") => {
772        $crate::TokenKind::AmpersandAmpersand
773    };
774    ("&&=") => {
775        $crate::TokenKind::AmpersandAmpersandEqual
776    };
777    ("array") => {
778        $crate::TokenKind::Array
779    };
780    ("(array)") => {
781        $crate::TokenKind::ArrayCast
782    };
783    ("->") => {
784        $crate::TokenKind::MinusGreaterThan
785    };
786    ("?->") => {
787        $crate::TokenKind::QuestionMinusGreaterThan
788    };
789    ("@") => {
790        $crate::TokenKind::At
791    };
792    ("as") => {
793        $crate::TokenKind::As
794    };
795    ("*") => {
796        $crate::TokenKind::Asterisk
797    };
798    ("#[") => {
799        $crate::TokenKind::HashLeftBracket
800    };
801    ("!") => {
802        $crate::TokenKind::Bang
803    };
804    ("!=") => {
805        $crate::TokenKind::BangEqual
806    };
807    ("<>") => {
808        $crate::TokenKind::LessThanGreaterThan
809    };
810    ("!==") => {
811        $crate::TokenKind::BangEqualEqual
812    };
813    ("<=>") => {
814        $crate::TokenKind::LessThanEqualGreaterThan
815    };
816    ("(bool)") => {
817        $crate::TokenKind::BoolCast
818    };
819    ("(boolean)") => {
820        $crate::TokenKind::BooleanCast
821    };
822    ("and") => {
823        $crate::TokenKind::And
824    };
825    ("or") => {
826        $crate::TokenKind::Or
827    };
828    ("break") => {
829        $crate::TokenKind::Break
830    };
831    ("callable") => {
832        $crate::TokenKind::Callable
833    };
834    ("^") => {
835        $crate::TokenKind::Caret
836    };
837    ("^=") => {
838        $crate::TokenKind::CaretEqual
839    };
840    ("case") => {
841        $crate::TokenKind::Case
842    };
843    ("catch") => {
844        $crate::TokenKind::Catch
845    };
846    ("class") => {
847        $crate::TokenKind::Class
848    };
849    ("__CLASS__") => {
850        $crate::TokenKind::ClassConstant
851    };
852    ("__TRAIT__") => {
853        $crate::TokenKind::TraitConstant
854    };
855    ("__FUNCTION__") => {
856        $crate::TokenKind::FunctionConstant
857    };
858    ("__METHOD__") => {
859        $crate::TokenKind::MethodConstant
860    };
861    ("__LINE__") => {
862        $crate::TokenKind::LineConstant
863    };
864    ("__FILE__") => {
865        $crate::TokenKind::FileConstant
866    };
867    ("clone") => {
868        $crate::TokenKind::Clone
869    };
870    ("-=") => {
871        $crate::TokenKind::MinusEqual
872    };
873    ("?>") => {
874        $crate::TokenKind::CloseTag
875    };
876    ("??") => {
877        $crate::TokenKind::QuestionQuestion
878    };
879    ("??=") => {
880        $crate::TokenKind::QuestionQuestionEqual
881    };
882    ("*=") => {
883        $crate::TokenKind::AsteriskEqual
884    };
885    (":") => {
886        $crate::TokenKind::Colon
887    };
888    (",") => {
889        $crate::TokenKind::Comma
890    };
891    ("// comment") => {
892        $crate::TokenKind::SingleLineComment
893    };
894    ("# comment") => {
895        $crate::TokenKind::HashComment
896    };
897    ("/* comment */") => {
898        $crate::TokenKind::MultiLineComment
899    };
900    ("/** comment */") => {
901        $crate::TokenKind::DocBlockComment
902    };
903    ("const") => {
904        $crate::TokenKind::Const
905    };
906    ("continue") => {
907        $crate::TokenKind::Continue
908    };
909    ("declare") => {
910        $crate::TokenKind::Declare
911    };
912    ("--") => {
913        $crate::TokenKind::MinusMinus
914    };
915    ("default") => {
916        $crate::TokenKind::Default
917    };
918    ("__DIR__") => {
919        $crate::TokenKind::DirConstant
920    };
921    ("/=") => {
922        $crate::TokenKind::SlashEqual
923    };
924    ("do") => {
925        $crate::TokenKind::Do
926    };
927    ("${") => {
928        $crate::TokenKind::DollarLeftBrace
929    };
930    (".") => {
931        $crate::TokenKind::Dot
932    };
933    (".=") => {
934        $crate::TokenKind::DotEqual
935    };
936    ("=>") => {
937        $crate::TokenKind::EqualGreaterThan
938    };
939    ("(double)") => {
940        $crate::TokenKind::DoubleCast
941    };
942    ("(real)") => {
943        $crate::TokenKind::RealCast
944    };
945    ("(float)") => {
946        $crate::TokenKind::FloatCast
947    };
948    ("::") => {
949        $crate::TokenKind::ColonColon
950    };
951    ("==") => {
952        $crate::TokenKind::EqualEqual
953    };
954    ("\"") => {
955        $crate::TokenKind::DoubleQuote
956    };
957    ("else") => {
958        $crate::TokenKind::Else
959    };
960    ("echo") => {
961        $crate::TokenKind::Echo
962    };
963    ("...") => {
964        $crate::TokenKind::DotDotDot
965    };
966    ("elseif") => {
967        $crate::TokenKind::ElseIf
968    };
969    ("empty") => {
970        $crate::TokenKind::Empty
971    };
972    ("enddeclare") => {
973        $crate::TokenKind::EndDeclare
974    };
975    ("endfor") => {
976        $crate::TokenKind::EndFor
977    };
978    ("endforeach") => {
979        $crate::TokenKind::EndForeach
980    };
981    ("endif") => {
982        $crate::TokenKind::EndIf
983    };
984    ("endswitch") => {
985        $crate::TokenKind::EndSwitch
986    };
987    ("endwhile") => {
988        $crate::TokenKind::EndWhile
989    };
990    ("enum") => {
991        $crate::TokenKind::Enum
992    };
993    ("=") => {
994        $crate::TokenKind::Equal
995    };
996    ("extends") => {
997        $crate::TokenKind::Extends
998    };
999    ("false") => {
1000        $crate::TokenKind::False
1001    };
1002    ("final") => {
1003        $crate::TokenKind::Final
1004    };
1005    ("finally") => {
1006        $crate::TokenKind::Finally
1007    };
1008    ("fn") => {
1009        $crate::TokenKind::Fn
1010    };
1011    ("for") => {
1012        $crate::TokenKind::For
1013    };
1014    ("foreach") => {
1015        $crate::TokenKind::Foreach
1016    };
1017    ("\\Fully\\Qualified\\Identifier") => {
1018        $crate::TokenKind::FullyQualifiedIdentifier
1019    };
1020    ("function") => {
1021        $crate::TokenKind::Function
1022    };
1023    ("goto") => {
1024        $crate::TokenKind::Goto
1025    };
1026    (">") => {
1027        $crate::TokenKind::GreaterThan
1028    };
1029    (">=") => {
1030        $crate::TokenKind::GreaterThanEqual
1031    };
1032    ("Identifier") => {
1033        $crate::TokenKind::Identifier
1034    };
1035    ("if") => {
1036        $crate::TokenKind::If
1037    };
1038    ("implements") => {
1039        $crate::TokenKind::Implements
1040    };
1041    ("include") => {
1042        $crate::TokenKind::Include
1043    };
1044    ("include_once") => {
1045        $crate::TokenKind::IncludeOnce
1046    };
1047    ("++") => {
1048        $crate::TokenKind::PlusPlus
1049    };
1050    ("instanceof") => {
1051        $crate::TokenKind::Instanceof
1052    };
1053    ("insteadof") => {
1054        $crate::TokenKind::Insteadof
1055    };
1056    ("exit") => {
1057        $crate::TokenKind::Exit
1058    };
1059    ("unset") => {
1060        $crate::TokenKind::Unset
1061    };
1062    ("isset") => {
1063        $crate::TokenKind::Isset
1064    };
1065    ("list") => {
1066        $crate::TokenKind::List
1067    };
1068    ("(int)") => {
1069        $crate::TokenKind::IntCast
1070    };
1071    ("(integer)") => {
1072        $crate::TokenKind::IntegerCast
1073    };
1074    ("interface") => {
1075        $crate::TokenKind::Interface
1076    };
1077    ("{") => {
1078        $crate::TokenKind::LeftBrace
1079    };
1080    ("[") => {
1081        $crate::TokenKind::LeftBracket
1082    };
1083    ("(") => {
1084        $crate::TokenKind::LeftParenthesis
1085    };
1086    (")") => {
1087        $crate::TokenKind::RightParenthesis
1088    };
1089    ("<<") => {
1090        $crate::TokenKind::LeftShift
1091    };
1092    ("<<=") => {
1093        $crate::TokenKind::LeftShiftEqual
1094    };
1095    (">>") => {
1096        $crate::TokenKind::RightShift
1097    };
1098    (">>=") => {
1099        $crate::TokenKind::RightShiftEqual
1100    };
1101    ("<") => {
1102        $crate::TokenKind::LessThan
1103    };
1104    ("<=") => {
1105        $crate::TokenKind::LessThanEqual
1106    };
1107    ("match") => {
1108        $crate::TokenKind::Match
1109    };
1110    ("-") => {
1111        $crate::TokenKind::Minus
1112    };
1113    ("namespace") => {
1114        $crate::TokenKind::Namespace
1115    };
1116    ("\\") => {
1117        $crate::TokenKind::NamespaceSeparator
1118    };
1119    ("__NAMESPACE__") => {
1120        $crate::TokenKind::NamespaceConstant
1121    };
1122    ("new") => {
1123        $crate::TokenKind::New
1124    };
1125    ("null") => {
1126        $crate::TokenKind::Null
1127    };
1128    ("(object)") => {
1129        $crate::TokenKind::ObjectCast
1130    };
1131    ("(unset)") => {
1132        $crate::TokenKind::UnsetCast
1133    };
1134    ("<?php") => {
1135        $crate::TokenKind::OpenTag
1136    };
1137    ("<?=") => {
1138        $crate::TokenKind::EchoTag
1139    };
1140    ("<?") => {
1141        $crate::TokenKind::ShortOpenTag
1142    };
1143    ("%") => {
1144        $crate::TokenKind::Percent
1145    };
1146    ("%=") => {
1147        $crate::TokenKind::PercentEqual
1148    };
1149    ("|") => {
1150        $crate::TokenKind::Pipe
1151    };
1152    ("|=") => {
1153        $crate::TokenKind::PipeEqual
1154    };
1155    ("+") => {
1156        $crate::TokenKind::Plus
1157    };
1158    ("+=") => {
1159        $crate::TokenKind::PlusEqual
1160    };
1161    ("**") => {
1162        $crate::TokenKind::AsteriskAsterisk
1163    };
1164    ("**=") => {
1165        $crate::TokenKind::AsteriskAsteriskEqual
1166    };
1167    ("private(set)") => {
1168        $crate::TokenKind::PrivateSet
1169    };
1170    ("private") => {
1171        $crate::TokenKind::Private
1172    };
1173    ("protected") => {
1174        $crate::TokenKind::Protected
1175    };
1176    ("protected(set)") => {
1177        $crate::TokenKind::ProtectedSet
1178    };
1179    ("public") => {
1180        $crate::TokenKind::Public
1181    };
1182    ("public(set)") => {
1183        $crate::TokenKind::PublicSet
1184    };
1185    ("Qualified\\Identifier") => {
1186        $crate::TokenKind::QualifiedIdentifier
1187    };
1188    ("?") => {
1189        $crate::TokenKind::Question
1190    };
1191    ("?:") => {
1192        $crate::TokenKind::QuestionColon
1193    };
1194    ("require") => {
1195        $crate::TokenKind::Require
1196    };
1197    ("require_once") => {
1198        $crate::TokenKind::RequireOnce
1199    };
1200    ("return") => {
1201        $crate::TokenKind::Return
1202    };
1203    ("}") => {
1204        $crate::TokenKind::RightBrace
1205    };
1206    ("]") => {
1207        $crate::TokenKind::RightBracket
1208    };
1209    (";") => {
1210        $crate::TokenKind::Semicolon
1211    };
1212    ("/") => {
1213        $crate::TokenKind::Slash
1214    };
1215    ("static") => {
1216        $crate::TokenKind::Static
1217    };
1218    ("(string)") => {
1219        $crate::TokenKind::StringCast
1220    };
1221    ("(binary)") => {
1222        $crate::TokenKind::BinaryCast
1223    };
1224    ("switch") => {
1225        $crate::TokenKind::Switch
1226    };
1227    ("throw") => {
1228        $crate::TokenKind::Throw
1229    };
1230    ("trait") => {
1231        $crate::TokenKind::Trait
1232    };
1233    ("===") => {
1234        $crate::TokenKind::EqualEqualEqual
1235    };
1236    ("true") => {
1237        $crate::TokenKind::True
1238    };
1239    ("try") => {
1240        $crate::TokenKind::Try
1241    };
1242    ("use") => {
1243        $crate::TokenKind::Use
1244    };
1245    ("var") => {
1246        $crate::TokenKind::Var
1247    };
1248    ("$variable") => {
1249        $crate::TokenKind::Variable
1250    };
1251    ("yield") => {
1252        $crate::TokenKind::Yield
1253    };
1254    ("while") => {
1255        $crate::TokenKind::While
1256    };
1257    ("~") => {
1258        $crate::TokenKind::Tilde
1259    };
1260    ("||") => {
1261        $crate::TokenKind::PipePipe
1262    };
1263    ("xor") => {
1264        $crate::TokenKind::Xor
1265    };
1266    ($name:ident) => {
1267        $crate::TokenKind::$name
1268    };
1269    ($first:tt | $($rest:tt)+) => {
1270        $crate::T![$first] | $crate::T![$($rest)+]
1271    };
1272    ($($kind:tt),+ $(,)?) => {
1273        &[$($crate::T![$kind]),+]
1274    };
1275}