1use 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 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 Word(Word),
219
220 Arrow,
222
223 Hash,
225
226 At,
228 Dot,
230
231 DotDotDot,
233 Bang,
235
236 LParen,
238 RParen,
240 LBracket,
242 RBracket,
244 LBrace,
246 RBrace,
248
249 Semi,
251 Comma,
253
254 BackQuote,
256 Template {
257 raw: Atom,
258 cooked: LexResult<Atom>,
259 },
260 Colon,
262 BinOp(BinOpToken),
263 AssignOp(AssignOp),
264
265 DollarLBrace,
267
268 QuestionMark,
270
271 PlusPlus,
273 MinusMinus,
275
276 Tilde,
278
279 Str {
281 value: Atom,
282 raw: Atom,
283 },
284
285 Regex(Atom, Atom),
287
288 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 EqEq,
407 NotEq,
409 EqEqEq,
411 NotEqEq,
413 Lt,
415 LtEq,
417 Gt,
419 GtEq,
421 LShift,
423 RShift,
425 ZeroFillRShift,
427
428 Add,
430 Sub,
432 Mul,
434 Div,
436 Mod,
438
439 BitOr,
441 BitXor,
443 BitAnd,
445
446 Exp,
454
455 LogicalOr,
457 LogicalAnd,
459
460 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 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#[derive(Clone, Copy, PartialEq, Eq, Hash)]
786pub enum Keyword {
787 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 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 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 #[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}