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_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 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(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 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
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#[derive(Clone, Copy, PartialEq, Eq, Hash)]
785pub enum Keyword {
786 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 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 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 #[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}