swc_ecma_lexer/
token.rs

1//! Ported from [babel/babylon][]
2//!
3//! [babel/babylon]:https://github.com/babel/babel/blob/2d378d076eb0c5fe63234a8b509886005c01d7ee/packages/babylon/src/tokenizer/types.js
4use std::{
5    borrow::Cow,
6    fmt::{self, Debug, Display, Formatter},
7};
8
9use num_bigint::BigInt as BigIntValue;
10use swc_atoms::{atom, Atom, AtomStore};
11use swc_common::{Span, Spanned};
12pub(crate) use swc_ecma_ast::{AssignOp, BinaryOp};
13
14pub(crate) use self::{Keyword::*, Token::*};
15use crate::{error::Error, lexer::LexResult};
16
17macro_rules! define_known_ident {
18    (
19        $(
20            $name:ident => $value:tt,
21        )*
22    ) => {
23        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24        #[non_exhaustive]
25        pub enum KnownIdent {
26            $(
27                $name
28            ),*
29        }
30
31        #[allow(unused)]
32        #[macro_export]
33        macro_rules! known_ident_token {
34            $(
35                ($value) => {
36                    $crate::token::TokenKind::Word($crate::token::WordKind::Ident(
37                        $crate::token::IdentKind::Known($crate::token::KnownIdent::$name),
38                    ))
39                };
40            )*
41        }
42
43        #[allow(unused)]
44        #[macro_export]
45        macro_rules! known_ident {
46            $(
47                ($value) => {
48                    $crate::token::KnownIdent::$name
49                };
50            )*
51        }
52        #[allow(unused)]
53        #[macro_export]
54        macro_rules! ident_like {
55            $(
56                ($value) => {
57                    $crate::token::IdentLike::Known(
58                        $crate::token::KnownIdent::$name
59                    )
60                };
61            )*
62        }
63
64        static STR_TO_KNOWN_IDENT: phf::Map<&'static str, KnownIdent> = phf::phf_map! {
65            $(
66                $value => KnownIdent::$name,
67            )*
68        };
69
70        impl From<KnownIdent> for swc_atoms::Atom {
71
72            fn from(s: KnownIdent) -> Self {
73                match s {
74                    $(
75                        KnownIdent::$name => atom!($value),
76                    )*
77                }
78            }
79        }
80        impl From<KnownIdent> for &'static str {
81
82            fn from(s: KnownIdent) -> Self {
83                match s {
84                    $(
85                        KnownIdent::$name => $value,
86                    )*
87                }
88            }
89        }
90    };
91}
92
93define_known_ident!(
94    Abstract => "abstract",
95    As => "as",
96    Async => "async",
97    From => "from",
98    Of => "of",
99    Type => "type",
100    Global => "global",
101    Static => "static",
102    Using => "using",
103    Readonly => "readonly",
104    Unique => "unique",
105    Keyof => "keyof",
106    Declare => "declare",
107    Enum => "enum",
108    Is => "is",
109    Infer => "infer",
110    Symbol => "symbol",
111    Undefined => "undefined",
112    Interface => "interface",
113    Implements => "implements",
114    Asserts => "asserts",
115    Require => "require",
116    Get => "get",
117    Set => "set",
118    Any => "any",
119    Intrinsic => "intrinsic",
120    Unknown => "unknown",
121    String => "string",
122    Object => "object",
123    Number => "number",
124    Bigint => "bigint",
125    Boolean => "boolean",
126    Never => "never",
127    Assert => "assert",
128    Namespace => "namespace",
129    Accessor => "accessor",
130    Meta => "meta",
131    Target => "target",
132    Satisfies => "satisfies",
133    Package => "package",
134    Protected => "protected",
135    Private => "private",
136    Public => "public",
137);
138
139impl std::str::FromStr for KnownIdent {
140    type Err = ();
141
142    fn from_str(s: &str) -> Result<Self, Self::Err> {
143        STR_TO_KNOWN_IDENT.get(s).cloned().ok_or(())
144    }
145}
146
147#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
148pub enum WordKind {
149    Keyword(Keyword),
150
151    Null,
152    True,
153    False,
154
155    Ident(IdentKind),
156}
157
158impl From<Keyword> for WordKind {
159    #[inline(always)]
160    fn from(kwd: Keyword) -> Self {
161        Self::Keyword(kwd)
162    }
163}
164
165#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
166pub enum IdentKind {
167    Known(KnownIdent),
168    Other,
169}
170
171#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
172pub enum TokenKind {
173    Word(WordKind),
174    Arrow,
175    Hash,
176    At,
177    Dot,
178    DotDotDot,
179    Bang,
180    LParen,
181    RParen,
182    LBracket,
183    RBracket,
184    LBrace,
185    RBrace,
186    Semi,
187    Comma,
188    BackQuote,
189    Template,
190    Colon,
191    BinOp(BinOpToken),
192    AssignOp(AssignOp),
193    DollarLBrace,
194    QuestionMark,
195    PlusPlus,
196    MinusMinus,
197    Tilde,
198    Str,
199    /// We abuse `token.raw` for flags
200    Regex,
201    Num,
202    BigInt,
203
204    JSXName,
205    JSXText,
206    JSXTagStart,
207    JSXTagEnd,
208
209    Shebang,
210    Error,
211}
212
213#[derive(Clone, PartialEq)]
214pub enum Token {
215    /// Identifier, "null", "true", "false".
216    ///
217    /// Contains `null` and ``
218    Word(Word),
219
220    /// '=>'
221    Arrow,
222
223    /// '#'
224    Hash,
225
226    /// '@'
227    At,
228    /// '.'
229    Dot,
230
231    /// '...'
232    DotDotDot,
233    /// '!'
234    Bang,
235
236    /// '('
237    LParen,
238    /// ')'
239    RParen,
240    /// `[`
241    LBracket,
242    /// ']'
243    RBracket,
244    /// '{'
245    LBrace,
246    /// '}'
247    RBrace,
248
249    /// ';'
250    Semi,
251    /// ','
252    Comma,
253
254    /// '`'
255    BackQuote,
256    Template {
257        raw: Atom,
258        cooked: LexResult<Atom>,
259    },
260    /// ':'
261    Colon,
262    BinOp(BinOpToken),
263    AssignOp(AssignOp),
264
265    /// '${'
266    DollarLBrace,
267
268    /// '?'
269    QuestionMark,
270
271    /// `++`
272    PlusPlus,
273    /// `--`
274    MinusMinus,
275
276    /// `~`
277    Tilde,
278
279    /// String literal. Span of this token contains quote.
280    Str {
281        value: Atom,
282        raw: Atom,
283    },
284
285    /// Regexp literal.
286    Regex(Atom, Atom),
287
288    /// TODO: Make Num as enum and separate decimal, binary, ..etc
289    Num {
290        value: f64,
291        raw: Atom,
292    },
293
294    BigInt {
295        value: Box<BigIntValue>,
296        raw: Atom,
297    },
298
299    JSXName {
300        name: Atom,
301    },
302    JSXText {
303        value: Atom,
304        raw: Atom,
305    },
306    JSXTagStart,
307    JSXTagEnd,
308
309    Shebang(Atom),
310    Error(Error),
311}
312
313impl Token {
314    pub fn kind(&self) -> TokenKind {
315        match self {
316            Self::Arrow => TokenKind::Arrow,
317            Self::Hash => TokenKind::Hash,
318            Self::At => TokenKind::At,
319            Self::Dot => TokenKind::Dot,
320            Self::DotDotDot => TokenKind::DotDotDot,
321            Self::Bang => TokenKind::Bang,
322            Self::LParen => TokenKind::LParen,
323            Self::RParen => TokenKind::RParen,
324            Self::LBracket => TokenKind::LBracket,
325            Self::RBracket => TokenKind::RBracket,
326            Self::LBrace => TokenKind::LBrace,
327            Self::RBrace => TokenKind::RBrace,
328            Self::Semi => TokenKind::Semi,
329            Self::Comma => TokenKind::Comma,
330            Self::BackQuote => TokenKind::BackQuote,
331            Self::Template { .. } => TokenKind::Template,
332            Self::Colon => TokenKind::Colon,
333            Self::BinOp(op) => TokenKind::BinOp(*op),
334            Self::AssignOp(op) => TokenKind::AssignOp(*op),
335            Self::DollarLBrace => TokenKind::DollarLBrace,
336            Self::QuestionMark => TokenKind::QuestionMark,
337            Self::PlusPlus => TokenKind::PlusPlus,
338            Self::MinusMinus => TokenKind::MinusMinus,
339            Self::Tilde => TokenKind::Tilde,
340            Self::Str { .. } => TokenKind::Str,
341            Self::Regex(..) => TokenKind::Regex,
342            Self::Num { .. } => TokenKind::Num,
343            Self::BigInt { .. } => TokenKind::BigInt,
344            Self::JSXName { .. } => TokenKind::JSXName,
345            Self::JSXText { .. } => TokenKind::JSXText,
346            Self::JSXTagStart => TokenKind::JSXTagStart,
347            Self::JSXTagEnd => TokenKind::JSXTagEnd,
348            Self::Shebang(..) => TokenKind::Shebang,
349            Self::Error(..) => TokenKind::Error,
350            Self::Word(w) => TokenKind::Word(w.kind()),
351        }
352    }
353}
354
355impl TokenKind {
356    pub const fn before_expr(self) -> bool {
357        match self {
358            Self::Word(w) => w.before_expr(),
359            Self::BinOp(w) => w.before_expr(),
360            Self::Arrow
361            | Self::DotDotDot
362            | Self::Bang
363            | Self::LParen
364            | Self::LBrace
365            | Self::LBracket
366            | Self::Semi
367            | Self::Comma
368            | Self::Colon
369            | Self::AssignOp(..)
370            | Self::DollarLBrace
371            | Self::QuestionMark
372            | Self::PlusPlus
373            | Self::MinusMinus
374            | Self::Tilde
375            | Self::JSXText { .. } => true,
376            _ => false,
377        }
378    }
379
380    pub const fn starts_expr(self) -> bool {
381        match self {
382            Self::Word(w) => w.starts_expr(),
383            Self::BinOp(w) => w.starts_expr(),
384            Self::Bang
385            | Self::LParen
386            | Self::LBrace
387            | Self::LBracket
388            | Self::BackQuote
389            | Self::DollarLBrace
390            | Self::PlusPlus
391            | Self::MinusMinus
392            | Self::Tilde
393            | Self::Str
394            | Self::Regex
395            | Self::Num
396            | Self::BigInt
397            | Self::JSXTagStart => true,
398            _ => false,
399        }
400    }
401}
402
403#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
404pub enum BinOpToken {
405    /// `==`
406    EqEq,
407    /// `!=`
408    NotEq,
409    /// `===`
410    EqEqEq,
411    /// `!==`
412    NotEqEq,
413    /// `<`
414    Lt,
415    /// `<=`
416    LtEq,
417    /// `>`
418    Gt,
419    /// `>=`
420    GtEq,
421    /// `<<`
422    LShift,
423    /// `>>`
424    RShift,
425    /// `>>>`
426    ZeroFillRShift,
427
428    /// `+`
429    Add,
430    /// `-`
431    Sub,
432    /// `*`
433    Mul,
434    /// `/`
435    Div,
436    /// `%`
437    Mod,
438
439    /// `|`
440    BitOr,
441    /// `^`
442    BitXor,
443    /// `&`
444    BitAnd,
445
446    // /// `in`
447    // #[kind(precedence = "7")]
448    // In,
449    // /// `instanceof`
450    // #[kind(precedence = "7")]
451    // InstanceOf,
452    /// `**`
453    Exp,
454
455    /// `||`
456    LogicalOr,
457    /// `&&`
458    LogicalAnd,
459
460    /// `??`
461    NullishCoalescing,
462}
463
464impl BinOpToken {
465    pub(crate) const fn starts_expr(self) -> bool {
466        matches!(self, Self::Add | Self::Sub)
467    }
468
469    pub(crate) const fn before_expr(self) -> bool {
470        true
471    }
472}
473
474#[derive(Debug, Clone, PartialEq)]
475pub struct TokenAndSpan {
476    pub token: Token,
477    /// Had a line break before this token?
478    pub had_line_break: bool,
479    pub span: Span,
480}
481
482impl Spanned for TokenAndSpan {
483    #[inline]
484    fn span(&self) -> Span {
485        self.span
486    }
487}
488
489#[derive(Clone, PartialEq, Eq, Hash)]
490pub enum Word {
491    Keyword(Keyword),
492
493    Null,
494    True,
495    False,
496
497    Ident(IdentLike),
498}
499
500#[derive(Clone, PartialEq, Eq, Hash)]
501pub enum IdentLike {
502    Known(KnownIdent),
503    Other(Atom),
504}
505
506impl From<&'_ str> for IdentLike {
507    fn from(s: &str) -> Self {
508        s.parse::<KnownIdent>()
509            .map(Self::Known)
510            .unwrap_or_else(|_| Self::Other(s.into()))
511    }
512}
513
514impl IdentLike {
515    pub(crate) fn from_str(atoms: &mut AtomStore, s: &str) -> IdentLike {
516        s.parse::<KnownIdent>()
517            .map(Self::Known)
518            .unwrap_or_else(|_| Self::Other(atoms.atom(s)))
519    }
520}
521
522impl Word {
523    pub fn from_str(atoms: &mut AtomStore, s: &str) -> Self {
524        match s {
525            "null" => Word::Null,
526            "true" => Word::True,
527            "false" => Word::False,
528            "await" => Await.into(),
529            "break" => Break.into(),
530            "case" => Case.into(),
531            "catch" => Catch.into(),
532            "continue" => Continue.into(),
533            "debugger" => Debugger.into(),
534            "default" => Default_.into(),
535            "do" => Do.into(),
536            "export" => Export.into(),
537            "else" => Else.into(),
538            "finally" => Finally.into(),
539            "for" => For.into(),
540            "function" => Function.into(),
541            "if" => If.into(),
542            "return" => Return.into(),
543            "switch" => Switch.into(),
544            "throw" => Throw.into(),
545            "try" => Try.into(),
546            "var" => Var.into(),
547            "let" => Let.into(),
548            "const" => Const.into(),
549            "while" => While.into(),
550            "with" => With.into(),
551            "new" => New.into(),
552            "this" => This.into(),
553            "super" => Super.into(),
554            "class" => Class.into(),
555            "extends" => Extends.into(),
556            "import" => Import.into(),
557            "yield" => Yield.into(),
558            "in" => In.into(),
559            "instanceof" => InstanceOf.into(),
560            "typeof" => TypeOf.into(),
561            "void" => Void.into(),
562            "delete" => Delete.into(),
563            _ => Word::Ident(IdentLike::from_str(atoms, s)),
564        }
565    }
566
567    pub(crate) fn kind(&self) -> WordKind {
568        match self {
569            Word::Keyword(k) => WordKind::Keyword(*k),
570            Word::Null => WordKind::Null,
571            Word::True => WordKind::True,
572            Word::False => WordKind::False,
573            Word::Ident(IdentLike::Known(i)) => WordKind::Ident(IdentKind::Known(*i)),
574            Word::Ident(IdentLike::Other(..)) => WordKind::Ident(IdentKind::Other),
575        }
576    }
577}
578
579impl WordKind {
580    pub(crate) const fn before_expr(self) -> bool {
581        match self {
582            Self::Keyword(k) => k.before_expr(),
583            _ => false,
584        }
585    }
586
587    pub(crate) const fn starts_expr(self) -> bool {
588        match self {
589            Self::Keyword(k) => k.starts_expr(),
590            _ => true,
591        }
592    }
593}
594
595impl AsRef<str> for IdentLike {
596    fn as_ref(&self) -> &str {
597        match self {
598            IdentLike::Known(k) => (*k).into(),
599            IdentLike::Other(s) => s.as_ref(),
600        }
601    }
602}
603
604impl From<Keyword> for Word {
605    fn from(kwd: Keyword) -> Self {
606        Word::Keyword(kwd)
607    }
608}
609
610impl From<Word> for Atom {
611    fn from(w: Word) -> Self {
612        match w {
613            Word::Keyword(k) => match k {
614                Await => "await",
615                Break => "break",
616                Case => "case",
617                Catch => "catch",
618                Continue => "continue",
619                Debugger => "debugger",
620                Default_ => "default",
621                Do => "do",
622                Else => "else",
623
624                Finally => "finally",
625                For => "for",
626
627                Function => "function",
628
629                If => "if",
630
631                Return => "return",
632
633                Switch => "switch",
634
635                Throw => "throw",
636
637                Try => "try",
638                Var => "var",
639                Let => "let",
640                Const => "const",
641                While => "while",
642                With => "with",
643
644                New => "new",
645                This => "this",
646                Super => "super",
647
648                Class => "class",
649
650                Extends => "extends",
651
652                Export => "export",
653                Import => "import",
654
655                Yield => "yield",
656
657                In => "in",
658                InstanceOf => "instanceof",
659
660                TypeOf => "typeof",
661
662                Void => "void",
663
664                Delete => "delete",
665            }
666            .into(),
667
668            Word::Null => "null".into(),
669            Word::True => "true".into(),
670            Word::False => "false".into(),
671
672            Word::Ident(w) => w.into(),
673        }
674    }
675}
676
677impl From<IdentLike> for Atom {
678    fn from(i: IdentLike) -> Self {
679        match i {
680            IdentLike::Known(i) => i.into(),
681            IdentLike::Other(i) => i,
682        }
683    }
684}
685
686impl Debug for Word {
687    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
688        match *self {
689            Word::Ident(ref s) => Display::fmt(s, f),
690            _ => {
691                let s: Atom = self.clone().into();
692                Display::fmt(&s, f)
693            }
694        }
695    }
696}
697
698impl Display for IdentLike {
699    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
700        match *self {
701            IdentLike::Known(ref s) => Display::fmt(s, f),
702            IdentLike::Other(ref s) => Display::fmt(s, f),
703        }
704    }
705}
706
707impl Display for KnownIdent {
708    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
709        let s: &'static str = (*self).into();
710
711        Display::fmt(s, f)
712    }
713}
714
715#[macro_export]
716macro_rules! declare_keyword {
717    ($(
718        $name:ident => $value:tt,
719    )*) => {
720        impl Keyword {
721            pub fn into_atom(self) -> Atom {
722                match self {
723                    $(Keyword::$name => atom!($value),)*
724                }
725            }
726        }
727    };
728}
729
730declare_keyword!(
731    Await => "await",
732    Break => "break",
733    Case => "case",
734    Catch => "catch",
735    Continue => "continue",
736    Debugger => "debugger",
737    Default_ => "default",
738    Do => "do",
739    Else => "else",
740
741    Finally => "finally",
742    For => "for",
743
744    Function => "function",
745
746    If => "if",
747
748    Return => "return",
749
750    Switch => "switch",
751
752    Throw => "throw",
753
754    Try => "try",
755    Var => "var",
756    Let => "let",
757    Const => "const",
758    While => "while",
759    With => "with",
760
761    New => "new",
762    This => "this",
763    Super => "super",
764
765    Class => "class",
766
767    Extends => "extends",
768
769    Export => "export",
770    Import => "import",
771
772    Yield => "yield",
773
774    In => "in",
775    InstanceOf => "instanceof",
776
777    TypeOf => "typeof",
778
779    Void => "void",
780
781    Delete => "delete",
782);
783
784/// Keywords
785#[derive(Clone, Copy, PartialEq, Eq, Hash)]
786pub enum Keyword {
787    /// Spec says this might be identifier.
788    Await,
789    Break,
790    Case,
791    Catch,
792    Continue,
793    Debugger,
794    Default_,
795    Do,
796    Else,
797
798    Finally,
799    For,
800
801    Function,
802
803    If,
804
805    Return,
806
807    Switch,
808
809    Throw,
810
811    Try,
812    Var,
813    Let,
814    Const,
815    While,
816    With,
817
818    New,
819    This,
820    Super,
821
822    Class,
823
824    Extends,
825
826    Export,
827    Import,
828
829    /// Spec says this might be identifier.
830    Yield,
831
832    In,
833    InstanceOf,
834    TypeOf,
835    Void,
836    Delete,
837}
838
839impl Keyword {
840    pub(crate) const fn before_expr(self) -> bool {
841        matches!(
842            self,
843            Self::Await
844                | Self::Case
845                | Self::Default_
846                | Self::Do
847                | Self::Else
848                | Self::Return
849                | Self::Throw
850                | Self::New
851                | Self::Extends
852                | Self::Yield
853                | Self::In
854                | Self::InstanceOf
855                | Self::TypeOf
856                | Self::Void
857                | Self::Delete
858        )
859    }
860
861    pub(crate) const fn starts_expr(self) -> bool {
862        matches!(
863            self,
864            Self::Await
865                | Self::Function
866                | Self::Throw
867                | Self::New
868                | Self::This
869                | Self::Super
870                | Self::Class
871                | Self::Import
872                | Self::Yield
873                | Self::TypeOf
874                | Self::Void
875                | Self::Delete
876        )
877    }
878}
879
880impl Debug for Keyword {
881    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
882        write!(f, "keyword '{}'", self.into_atom())?;
883
884        Ok(())
885    }
886}
887
888impl From<BinOpToken> for BinaryOp {
889    fn from(t: BinOpToken) -> Self {
890        use self::BinaryOp::*;
891        match t {
892            BinOpToken::EqEq => EqEq,
893            BinOpToken::NotEq => NotEq,
894            BinOpToken::EqEqEq => EqEqEq,
895            BinOpToken::NotEqEq => NotEqEq,
896            BinOpToken::Lt => Lt,
897            BinOpToken::LtEq => LtEq,
898            BinOpToken::Gt => Gt,
899            BinOpToken::GtEq => GtEq,
900            BinOpToken::LShift => LShift,
901            BinOpToken::RShift => RShift,
902            BinOpToken::ZeroFillRShift => ZeroFillRShift,
903            BinOpToken::Add => Add,
904            BinOpToken::Sub => Sub,
905            BinOpToken::Mul => Mul,
906            BinOpToken::Div => Div,
907            BinOpToken::Mod => Mod,
908            BinOpToken::BitOr => BitOr,
909            BinOpToken::BitXor => BitXor,
910            BinOpToken::BitAnd => BitAnd,
911            BinOpToken::LogicalOr => LogicalOr,
912            BinOpToken::LogicalAnd => LogicalAnd,
913            BinOpToken::Exp => Exp,
914            BinOpToken::NullishCoalescing => NullishCoalescing,
915        }
916    }
917}
918
919impl TokenKind {
920    /// Returns true if `self` can follow keyword let.
921    ///
922    /// e.g. `let a = xx;`, `let {a:{}} = 1`
923    pub fn follows_keyword_let(self, _strict: bool) -> bool {
924        match self {
925            Self::Word(WordKind::Keyword(Keyword::Let))
926            | TokenKind::LBrace
927            | TokenKind::LBracket
928            | Self::Word(WordKind::Ident(..))
929            | TokenKind::Word(WordKind::Keyword(Keyword::Yield))
930            | TokenKind::Word(WordKind::Keyword(Keyword::Await)) => true,
931            _ => false,
932        }
933    }
934}
935
936impl Word {
937    pub fn cow(&self) -> Cow<Atom> {
938        match self {
939            Word::Keyword(k) => Cow::Owned(k.into_atom()),
940            Word::Ident(IdentLike::Known(w)) => Cow::Owned((*w).into()),
941            Word::Ident(IdentLike::Other(w)) => Cow::Borrowed(w),
942            Word::False => Cow::Owned(atom!("false")),
943            Word::True => Cow::Owned(atom!("true")),
944            Word::Null => Cow::Owned(atom!("null")),
945        }
946    }
947}
948
949impl Debug for Token {
950    /// This method is called only in the case of parsing failure.
951    #[cold]
952    #[inline(never)]
953    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
954        match self {
955            Token::Word(w) => write!(f, "{w:?}")?,
956            Arrow => write!(f, "=>")?,
957            Hash => write!(f, "#")?,
958            At => write!(f, "@")?,
959            Dot => write!(f, ".")?,
960            DotDotDot => write!(f, "...")?,
961            Bang => write!(f, "!")?,
962            LParen => write!(f, "(")?,
963            RParen => write!(f, ")")?,
964            LBracket => write!(f, "[")?,
965            RBracket => write!(f, "]")?,
966            LBrace => write!(f, "{{")?,
967            RBrace => write!(f, "}}")?,
968            Semi => write!(f, ";")?,
969            Comma => write!(f, ",")?,
970            BackQuote => write!(f, "`")?,
971            Template { raw, .. } => write!(f, "template token ({raw})")?,
972            Colon => write!(f, ":")?,
973            BinOp(op) => write!(f, "{}", BinaryOp::from(*op).as_str())?,
974            AssignOp(op) => write!(f, "{}", op.as_str())?,
975            DollarLBrace => write!(f, "${{")?,
976            QuestionMark => write!(f, "?")?,
977            PlusPlus => write!(f, "++")?,
978            MinusMinus => write!(f, "--")?,
979            Tilde => write!(f, "~")?,
980            Str { value, raw } => write!(f, "string literal ({value}, {raw})")?,
981            Regex(exp, flags) => write!(f, "regexp literal ({exp}, {flags})")?,
982            Num { value, raw, .. } => write!(f, "numeric literal ({value}, {raw})")?,
983            BigInt { value, raw } => write!(f, "bigint literal ({value}, {raw})")?,
984            JSXName { name } => write!(f, "jsx name ({name})")?,
985            JSXText { raw, .. } => write!(f, "jsx text ({raw})")?,
986            JSXTagStart => write!(f, "< (jsx tag start)")?,
987            JSXTagEnd => write!(f, "> (jsx tag end)")?,
988            Shebang(_) => write!(f, "#!")?,
989            Token::Error(e) => write!(f, "<lexing error: {e:?}>")?,
990        }
991
992        Ok(())
993    }
994}