swc_ecma_parser/
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_rules! known_ident_token {
33            $(
34                ($value) => {
35                    crate::token::TokenKind::Word(crate::token::WordKind::Ident(
36                        crate::token::IdentKind::Known(crate::token::KnownIdent::$name),
37                    ))
38                };
39            )*
40        }
41
42        #[allow(unused)]
43        macro_rules! known_ident {
44            $(
45                ($value) => {
46                    crate::token::KnownIdent::$name
47                };
48            )*
49        }
50        #[allow(unused)]
51        macro_rules! ident_like {
52            $(
53                ($value) => {
54                    crate::token::IdentLike::Known(
55                        crate::token::KnownIdent::$name
56                    )
57                };
58            )*
59        }
60
61        static STR_TO_KNOWN_IDENT: phf::Map<&'static str, KnownIdent> = phf::phf_map! {
62            $(
63                $value => KnownIdent::$name,
64            )*
65        };
66
67
68
69
70        impl From<KnownIdent> for 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(crate) 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(crate) 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(crate) 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
715macro_rules! declare_keyword {
716    ($(
717        $name:ident => $value:tt,
718    )*) => {
719        impl Keyword {
720            pub(crate)  fn into_atom(self) -> Atom {
721                match self {
722                    $(Keyword::$name => atom!($value),)*
723                }
724            }
725        }
726    };
727}
728
729declare_keyword!(
730    Await => "await",
731    Break => "break",
732    Case => "case",
733    Catch => "catch",
734    Continue => "continue",
735    Debugger => "debugger",
736    Default_ => "default",
737    Do => "do",
738    Else => "else",
739
740    Finally => "finally",
741    For => "for",
742
743    Function => "function",
744
745    If => "if",
746
747    Return => "return",
748
749    Switch => "switch",
750
751    Throw => "throw",
752
753    Try => "try",
754    Var => "var",
755    Let => "let",
756    Const => "const",
757    While => "while",
758    With => "with",
759
760    New => "new",
761    This => "this",
762    Super => "super",
763
764    Class => "class",
765
766    Extends => "extends",
767
768    Export => "export",
769    Import => "import",
770
771    Yield => "yield",
772
773    In => "in",
774    InstanceOf => "instanceof",
775
776    TypeOf => "typeof",
777
778    Void => "void",
779
780    Delete => "delete",
781);
782
783/// Keywords
784#[derive(Clone, Copy, PartialEq, Eq, Hash)]
785pub enum Keyword {
786    /// Spec says this might be identifier.
787    Await,
788    Break,
789    Case,
790    Catch,
791    Continue,
792    Debugger,
793    Default_,
794    Do,
795    Else,
796
797    Finally,
798    For,
799
800    Function,
801
802    If,
803
804    Return,
805
806    Switch,
807
808    Throw,
809
810    Try,
811    Var,
812    Let,
813    Const,
814    While,
815    With,
816
817    New,
818    This,
819    Super,
820
821    Class,
822
823    Extends,
824
825    Export,
826    Import,
827
828    /// Spec says this might be identifier.
829    Yield,
830
831    In,
832    InstanceOf,
833    TypeOf,
834    Void,
835    Delete,
836}
837
838impl Keyword {
839    pub(crate) const fn before_expr(self) -> bool {
840        matches!(
841            self,
842            Self::Await
843                | Self::Case
844                | Self::Default_
845                | Self::Do
846                | Self::Else
847                | Self::Return
848                | Self::Throw
849                | Self::New
850                | Self::Extends
851                | Self::Yield
852                | Self::In
853                | Self::InstanceOf
854                | Self::TypeOf
855                | Self::Void
856                | Self::Delete
857        )
858    }
859
860    pub(crate) const fn starts_expr(self) -> bool {
861        matches!(
862            self,
863            Self::Await
864                | Self::Function
865                | Self::Throw
866                | Self::New
867                | Self::This
868                | Self::Super
869                | Self::Class
870                | Self::Import
871                | Self::Yield
872                | Self::TypeOf
873                | Self::Void
874                | Self::Delete
875        )
876    }
877}
878
879impl Debug for Keyword {
880    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
881        write!(f, "keyword '{}'", self.into_atom())?;
882
883        Ok(())
884    }
885}
886
887impl From<BinOpToken> for BinaryOp {
888    fn from(t: BinOpToken) -> Self {
889        use self::BinaryOp::*;
890        match t {
891            BinOpToken::EqEq => EqEq,
892            BinOpToken::NotEq => NotEq,
893            BinOpToken::EqEqEq => EqEqEq,
894            BinOpToken::NotEqEq => NotEqEq,
895            BinOpToken::Lt => Lt,
896            BinOpToken::LtEq => LtEq,
897            BinOpToken::Gt => Gt,
898            BinOpToken::GtEq => GtEq,
899            BinOpToken::LShift => LShift,
900            BinOpToken::RShift => RShift,
901            BinOpToken::ZeroFillRShift => ZeroFillRShift,
902            BinOpToken::Add => Add,
903            BinOpToken::Sub => Sub,
904            BinOpToken::Mul => Mul,
905            BinOpToken::Div => Div,
906            BinOpToken::Mod => Mod,
907            BinOpToken::BitOr => BitOr,
908            BinOpToken::BitXor => BitXor,
909            BinOpToken::BitAnd => BitAnd,
910            BinOpToken::LogicalOr => LogicalOr,
911            BinOpToken::LogicalAnd => LogicalAnd,
912            BinOpToken::Exp => Exp,
913            BinOpToken::NullishCoalescing => NullishCoalescing,
914        }
915    }
916}
917
918impl TokenKind {
919    /// Returns true if `self` can follow keyword let.
920    ///
921    /// e.g. `let a = xx;`, `let {a:{}} = 1`
922    pub(crate) fn follows_keyword_let(self, _strict: bool) -> bool {
923        match self {
924            Self::Word(WordKind::Keyword(Keyword::Let))
925            | TokenKind::LBrace
926            | TokenKind::LBracket
927            | Self::Word(WordKind::Ident(..))
928            | TokenKind::Word(WordKind::Keyword(Keyword::Yield))
929            | TokenKind::Word(WordKind::Keyword(Keyword::Await)) => true,
930            _ => false,
931        }
932    }
933}
934
935impl Word {
936    pub(crate) fn cow(&self) -> Cow<Atom> {
937        match self {
938            Word::Keyword(k) => Cow::Owned(k.into_atom()),
939            Word::Ident(IdentLike::Known(w)) => Cow::Owned((*w).into()),
940            Word::Ident(IdentLike::Other(w)) => Cow::Borrowed(w),
941            Word::False => Cow::Owned(atom!("false")),
942            Word::True => Cow::Owned(atom!("true")),
943            Word::Null => Cow::Owned(atom!("null")),
944        }
945    }
946}
947
948impl Debug for Token {
949    /// This method is called only in the case of parsing failure.
950    #[cold]
951    #[inline(never)]
952    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
953        match self {
954            Token::Word(w) => write!(f, "{:?}", w)?,
955            Arrow => write!(f, "=>")?,
956            Hash => write!(f, "#")?,
957            At => write!(f, "@")?,
958            Dot => write!(f, ".")?,
959            DotDotDot => write!(f, "...")?,
960            Bang => write!(f, "!")?,
961            LParen => write!(f, "(")?,
962            RParen => write!(f, ")")?,
963            LBracket => write!(f, "[")?,
964            RBracket => write!(f, "]")?,
965            LBrace => write!(f, "{{")?,
966            RBrace => write!(f, "}}")?,
967            Semi => write!(f, ";")?,
968            Comma => write!(f, ",")?,
969            BackQuote => write!(f, "`")?,
970            Template { raw, .. } => write!(f, "template token ({})", raw)?,
971            Colon => write!(f, ":")?,
972            BinOp(op) => write!(f, "{}", BinaryOp::from(*op).as_str())?,
973            AssignOp(op) => write!(f, "{}", op.as_str())?,
974            DollarLBrace => write!(f, "${{")?,
975            QuestionMark => write!(f, "?")?,
976            PlusPlus => write!(f, "++")?,
977            MinusMinus => write!(f, "--")?,
978            Tilde => write!(f, "~")?,
979            Str { value, raw } => write!(f, "string literal ({}, {})", value, raw)?,
980            Regex(exp, flags) => write!(f, "regexp literal ({}, {})", exp, flags)?,
981            Num { value, raw, .. } => write!(f, "numeric literal ({}, {})", value, raw)?,
982            BigInt { value, raw } => write!(f, "bigint literal ({}, {})", value, raw)?,
983            JSXName { name } => write!(f, "jsx name ({})", name)?,
984            JSXText { raw, .. } => write!(f, "jsx text ({})", raw)?,
985            JSXTagStart => write!(f, "< (jsx tag start)")?,
986            JSXTagEnd => write!(f, "> (jsx tag end)")?,
987            Shebang(_) => write!(f, "#!")?,
988            Token::Error(e) => write!(f, "<lexing error: {:?}>", e)?,
989        }
990
991        Ok(())
992    }
993}