1use std::fmt::{self, Display};
4
5use oxc_data_structures::fieldless_enum;
6
7fieldless_enum! {
9 #[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
13 #[repr(u8)]
14 #[non_exhaustive]
15 pub enum Kind {
16 #[default]
17 Eof = 0,
18 Undetermined,
19 Skip, HashbangComment,
22 Ident,
24 Await,
26 Break,
27 Case,
28 Catch,
29 Class,
30 Const,
31 Continue,
32 Debugger,
33 Default,
34 Delete,
35 Do,
36 Else,
37 Enum,
38 Export,
39 Extends,
40 Finally,
41 For,
42 Function,
43 If,
44 Import,
45 In,
46 Instanceof,
47 New,
48 Return,
49 Super,
50 Switch,
51 This,
52 Throw,
53 Try,
54 Typeof,
55 Var,
56 Void,
57 While,
58 With,
59 Async,
61 From,
62 Get,
63 Meta, Of,
65 Set,
66 Target, Accessor, Source, Defer, Abstract,
72 As,
73 Asserts,
74 Assert,
75 Any,
76 Boolean,
77 Constructor,
78 Declare,
79 Infer,
80 Intrinsic,
81 Is,
82 KeyOf,
83 Module,
84 Namespace,
85 Never,
86 Out,
87 Readonly,
88 Require,
89 Number, Object,
91 Satisfies,
92 String, Symbol,
94 Type,
95 Undefined,
96 Unique,
97 Using,
98 Unknown,
99 Global,
100 BigInt, Override,
102 Implements,
104 Interface,
105 Let,
106 Package,
107 Private,
108 Protected,
109 Public,
110 Static,
111 Yield,
112 True,
116 False,
117 Null,
118 Amp, Amp2,
121 Amp2Eq,
122 AmpEq,
123 Bang, Caret,
125 CaretEq,
126 Colon,
127 Comma,
128 Dot,
129 Dot3, Eq,
131 Eq2,
132 Eq3,
133 GtEq, LAngle,
135 LBrack,
136 LCurly,
137 LParen,
138 LtEq, Minus,
140 Minus2,
141 MinusEq,
142 Neq,
143 Neq2,
144 Percent,
145 PercentEq,
146 Pipe,
147 Pipe2,
148 Pipe2Eq,
149 PipeEq,
150 Plus,
151 Plus2,
152 PlusEq,
153 Question,
154 Question2,
155 Question2Eq,
156 QuestionDot,
157 RAngle,
158 RBrack,
159 RCurly,
160 RParen,
161 Semicolon,
162 ShiftLeft, ShiftLeftEq, ShiftRight, ShiftRight3, ShiftRight3Eq, ShiftRightEq, Slash,
169 SlashEq,
170 Star,
171 Star2,
172 Star2Eq,
173 StarEq,
174 Tilde,
175 Arrow,
177 Decimal,
179 Float,
180 Binary,
181 Octal,
182 Hex,
183 PositiveExponential,
185 NegativeExponential,
187 DecimalBigInt,
189 BinaryBigInt,
190 OctalBigInt,
191 HexBigInt,
192 Str,
195 RegExp,
197 NoSubstitutionTemplate,
199 TemplateHead,
200 TemplateMiddle,
201 TemplateTail,
202 PrivateIdentifier,
204 JSXText,
206 At,
208 }
209}
210
211#[allow(clippy::enum_glob_use, clippy::allow_attributes)]
212use Kind::*;
213
214impl Kind {
215 #[inline]
216 pub const fn is_eof(self) -> bool {
217 matches!(self, Eof)
218 }
219
220 #[rustfmt::skip]
221 #[inline]
222 pub const fn is_number(self) -> bool {
223 matches!(
224 self,
225 Decimal | Float | Binary | Octal | Hex | PositiveExponential | NegativeExponential
226 | DecimalBigInt | BinaryBigInt | OctalBigInt | HexBigInt
227 )
228 }
229
230 #[inline] pub fn matches_number_byte(self, b: u8) -> bool {
232 match self {
233 Decimal => b.is_ascii_digit(),
234 Binary => matches!(b, b'0'..=b'1'),
235 Octal => matches!(b, b'0'..=b'7'),
236 Hex => b.is_ascii_hexdigit(),
237 _ => unreachable!(),
238 }
239 }
240
241 #[inline]
244 pub const fn is_identifier_reference(
245 self,
246 is_yield_context: bool,
247 is_await_context: bool,
248 ) -> bool {
249 self.is_identifier()
250 || (!is_yield_context && matches!(self, Yield))
251 || (!is_await_context && matches!(self, Await))
252 }
253
254 #[inline]
256 pub const fn is_binding_identifier(self) -> bool {
257 self.is_identifier() || matches!(self, Yield | Await)
258 }
259
260 #[inline]
262 pub const fn is_label_identifier(self, is_yield_context: bool, is_await_context: bool) -> bool {
263 self.is_identifier()
264 || (!is_yield_context && matches!(self, Yield))
265 || (!is_await_context && matches!(self, Await))
266 }
267
268 #[inline]
271 pub const fn is_identifier(self) -> bool {
272 self.is_identifier_name() && !self.is_reserved_keyword()
273 }
274
275 #[inline]
279 pub const fn is_ts_identifier(self, is_yield_context: bool, is_await_context: bool) -> bool {
280 self.is_identifier_reference(is_yield_context, is_await_context)
281 && !self.is_strict_mode_contextual_keyword()
282 && !self.is_contextual_keyword()
283 }
284
285 #[inline]
288 pub const fn is_identifier_name(self) -> bool {
289 matches!(self, Ident) || matches!(self as u8, x if x >= Await as u8 && x <= Null as u8)
290 }
291
292 #[inline]
298 pub const fn is_after_let(self) -> bool {
299 !matches!(self, In | Instanceof)
300 && (matches!(self, LCurly | LBrack | Ident) || self.is_any_keyword())
301 }
302
303 #[inline]
310 pub const fn is_literal(self) -> bool {
311 matches!(self, Null | True | False | Str | RegExp) || self.is_number()
312 }
313
314 #[inline]
315 pub const fn is_after_await_or_yield(self) -> bool {
316 !self.is_binary_operator() && (self.is_literal() || self.is_identifier_name())
317 }
318
319 #[inline]
325 pub const fn is_literal_property_name(self) -> bool {
326 self.is_identifier_name() || matches!(self, Str) || self.is_number()
327 }
328
329 #[inline]
330 pub const fn is_identifier_or_keyword(self) -> bool {
331 self.is_literal_property_name() || matches!(self, PrivateIdentifier)
332 }
333
334 #[rustfmt::skip]
335 #[inline]
336 pub const fn is_assignment_operator(self) -> bool {
337 matches!(
338 self,
339 Eq | PlusEq | MinusEq | StarEq | SlashEq | PercentEq | ShiftLeftEq | ShiftRightEq
340 | ShiftRight3Eq | Pipe2Eq | Amp2Eq | PipeEq | CaretEq | AmpEq | Question2Eq | Star2Eq
341 )
342 }
343
344 #[rustfmt::skip]
345 #[inline]
346 pub const fn is_binary_operator(self) -> bool {
347 matches!(
348 self,
349 Eq2 | Neq | Eq3 | Neq2 | LAngle | LtEq | RAngle | GtEq | ShiftLeft | ShiftRight | ShiftRight3
350 | Plus | Minus | Star | Slash | Percent | Pipe | Caret | Amp | In | Instanceof | Star2
351 )
352 }
353
354 #[inline]
355 pub const fn is_logical_operator(self) -> bool {
356 matches!(self, Pipe2 | Amp2 | Question2)
357 }
358
359 #[inline]
360 pub const fn is_unary_operator(self) -> bool {
361 matches!(self, Minus | Plus | Bang | Tilde | Typeof | Void | Delete)
362 }
363
364 #[inline]
365 pub const fn is_update_operator(self) -> bool {
366 matches!(self, Plus2 | Minus2)
367 }
368
369 #[inline]
371 pub const fn is_any_keyword(self) -> bool {
372 self.is_reserved_keyword()
381 || self.is_contextual_keyword()
382 || self.is_strict_mode_contextual_keyword()
383 || self.is_future_reserved_keyword()
384 }
385
386 #[rustfmt::skip]
387 #[inline]
388 pub const fn is_reserved_keyword(self) -> bool {
389 matches!(
390 self,
391 Await | Break | Case | Catch | Class | Const | Continue | Debugger | Default
392 | Delete | Do | Else | Enum | Export | Extends | False | Finally | For | Function | If
393 | Import | In | Instanceof | New | Null | Return | Super | Switch | This | Throw
394 | True | Try | Typeof | Var | Void | While | With | Yield
395 )
396 }
397
398 #[rustfmt::skip]
399 #[inline]
400 pub const fn is_strict_mode_contextual_keyword(self) -> bool {
401 matches!(self, Let | Static | Implements | Interface | Package | Private | Protected | Public)
402 }
403
404 #[rustfmt::skip]
405 #[inline]
406 pub const fn is_contextual_keyword(self) -> bool {
407 matches!(
408 self,
409 Async | From | Get | Meta | Of | Set | Target | Accessor | Abstract | As | Asserts | Assert
410 | Any | Boolean | Constructor | Declare | Infer | Intrinsic | Is | KeyOf | Module | Namespace
411 | Never | Out | Readonly | Require | Number | Object | Satisfies | String | Symbol | Type
412 | Undefined | Unique | Unknown | Using | Global | BigInt | Override | Source | Defer
413 )
414 }
415
416 #[rustfmt::skip]
417 #[inline]
418 pub const fn is_future_reserved_keyword(self) -> bool {
419 matches!(self, Implements | Interface | Package | Private | Protected | Public | Static)
420 }
421
422 #[inline]
423 pub const fn is_template_start_of_tagged_template(self) -> bool {
424 matches!(self, NoSubstitutionTemplate | TemplateHead)
425 }
426
427 #[rustfmt::skip]
428 #[inline]
429 pub const fn is_modifier_kind(self) -> bool {
430 matches!(
431 self,
432 Abstract | Accessor | Async | Const | Declare
433 | In | Out | Public | Private | Protected | Readonly | Static | Override
434 | Default | Export
435 )
436 }
437
438 #[inline]
439 pub const fn is_binding_identifier_or_private_identifier_or_pattern(self) -> bool {
440 matches!(self, LCurly | LBrack | PrivateIdentifier) || self.is_binding_identifier()
441 }
442
443 #[cold]
444 pub fn match_keyword(s: &str) -> Self {
445 let len = s.len();
446 if len <= 1 || len >= 12 || !unsafe { s.as_bytes().get_unchecked(0) }.is_ascii_lowercase() {
448 return Ident;
449 }
450 Self::match_keyword_impl(s)
451 }
452
453 fn match_keyword_impl(s: &str) -> Self {
454 match s {
455 "as" => As,
456 "do" => Do,
457 "if" => If,
458 "in" => In,
459 "is" => Is,
460 "of" => Of,
461
462 "any" => Any,
463 "for" => For,
464 "get" => Get,
465 "let" => Let,
466 "new" => New,
467 "out" => Out,
468 "set" => Set,
469 "try" => Try,
470 "var" => Var,
471
472 "case" => Case,
473 "else" => Else,
474 "enum" => Enum,
475 "from" => From,
476 "meta" => Meta,
477 "null" => Null,
478 "this" => This,
479 "true" => True,
480 "type" => Type,
481 "void" => Void,
482 "with" => With,
483
484 "async" => Async,
485 "await" => Await,
486 "break" => Break,
487 "catch" => Catch,
488 "class" => Class,
489 "const" => Const,
490 "false" => False,
491 "infer" => Infer,
492 "keyof" => KeyOf,
493 "never" => Never,
494 "super" => Super,
495 "throw" => Throw,
496 "using" => Using,
497 "while" => While,
498 "yield" => Yield,
499 "defer" => Defer,
500
501 "assert" => Assert,
502 "bigint" => BigInt,
503 "delete" => Delete,
504 "export" => Export,
505 "global" => Global,
506 "import" => Import,
507 "module" => Module,
508 "number" => Number,
509 "object" => Object,
510 "public" => Public,
511 "return" => Return,
512 "static" => Static,
513 "string" => String,
514 "switch" => Switch,
515 "symbol" => Symbol,
516 "target" => Target,
517 "typeof" => Typeof,
518 "unique" => Unique,
519 "source" => Source,
520
521 "asserts" => Asserts,
522 "boolean" => Boolean,
523 "declare" => Declare,
524 "default" => Default,
525 "extends" => Extends,
526 "finally" => Finally,
527 "package" => Package,
528 "private" => Private,
529 "require" => Require,
530 "unknown" => Unknown,
531
532 "abstract" => Abstract,
533 "accessor" => Accessor,
534 "continue" => Continue,
535 "debugger" => Debugger,
536 "function" => Function,
537 "override" => Override,
538 "readonly" => Readonly,
539
540 "interface" => Interface,
541 "intrinsic" => Intrinsic,
542 "namespace" => Namespace,
543 "protected" => Protected,
544 "satisfies" => Satisfies,
545 "undefined" => Undefined,
546
547 "implements" => Implements,
548 "instanceof" => Instanceof,
549
550 "constructor" => Constructor,
551 _ => Ident,
552 }
553 }
554
555 pub fn to_str(self) -> &'static str {
556 #[expect(clippy::match_same_arms)]
557 match self {
558 Undetermined => "Unknown",
559 Eof => "EOF",
560 Skip => "Skipped",
561 HashbangComment => "#!",
562 Ident => "Identifier",
563 Await => "await",
564 Break => "break",
565 Case => "case",
566 Catch => "catch",
567 Class => "class",
568 Const => "const",
569 Continue => "continue",
570 Debugger => "debugger",
571 Default => "default",
572 Delete => "delete",
573 Do => "do",
574 Else => "else",
575 Enum => "enum",
576 Export => "export",
577 Extends => "extends",
578 Finally => "finally",
579 For => "for",
580 Function => "function",
581 Using => "using",
582 If => "if",
583 Import => "import",
584 In => "in",
585 Instanceof => "instanceof",
586 New => "new",
587 Return => "return",
588 Super => "super",
589 Switch => "switch",
590 This => "this",
591 Throw => "throw",
592 Try => "try",
593 Typeof => "typeof",
594 Var => "var",
595 Void => "void",
596 While => "while",
597 With => "with",
598 As => "as",
599 Async => "async",
600 From => "from",
601 Get => "get",
602 Meta => "meta",
603 Of => "of",
604 Set => "set",
605 Asserts => "asserts",
606 Accessor => "accessor",
607 Abstract => "abstract",
608 Readonly => "readonly",
609 Declare => "declare",
610 Override => "override",
611 Type => "type",
612 Target => "target",
613 Source => "source",
614 Defer => "defer",
615 Implements => "implements",
616 Interface => "interface",
617 Package => "package",
618 Private => "private",
619 Protected => "protected",
620 Public => "public",
621 Static => "static",
622 Let => "let",
623 Yield => "yield",
624 Amp => "&",
625 Amp2 => "&&",
626 Amp2Eq => "&&=",
627 AmpEq => "&=",
628 Bang => "!",
629 Caret => "^",
630 CaretEq => "^=",
631 Colon => ":",
632 Comma => ",",
633 Dot => ".",
634 Dot3 => "...",
635 Eq => "=",
636 Eq2 => "==",
637 Eq3 => "===",
638 GtEq => ">=",
639 LAngle => "<",
640 LBrack => "[",
641 LCurly => "{",
642 LParen => "(",
643 LtEq => "<=",
644 Minus => "-",
645 Minus2 => "--",
646 MinusEq => "-=",
647 Neq => "!=",
648 Neq2 => "!==",
649 Percent => "%",
650 PercentEq => "%=",
651 Pipe => "|",
652 Pipe2 => "||",
653 Pipe2Eq => "||=",
654 PipeEq => "|=",
655 Plus => "+",
656 Plus2 => "++",
657 PlusEq => "+=",
658 Question => "?",
659 Question2 => "??",
660 Question2Eq => "??=",
661 QuestionDot => "?.",
662 RAngle => ">",
663 RBrack => "]",
664 RCurly => "}",
665 RParen => ")",
666 Semicolon => ";",
667 ShiftLeft => "<<",
668 ShiftLeftEq => "<<=",
669 ShiftRight => ">>",
670 ShiftRight3 => ">>>",
671 ShiftRight3Eq => ">>>=",
672 ShiftRightEq => ">>=",
673 Slash => "/",
674 SlashEq => "/=",
675 Star => "*",
676 Star2 => "**",
677 Star2Eq => "**=",
678 StarEq => "*=",
679 Tilde => "~",
680 Arrow => "=>",
681 Null => "null",
682 True => "true",
683 False => "false",
684 Decimal => "decimal",
685 Float | PositiveExponential | NegativeExponential => "float",
686 Binary => "binary",
687 Octal => "octal",
688 Hex => "hex",
689 DecimalBigInt => "decimal bigint",
690 BinaryBigInt => "binary bigint",
691 OctalBigInt => "octal bigint",
692 HexBigInt => "hex bigint",
693 Str | String => "string",
694 RegExp => "/regexp/",
695 NoSubstitutionTemplate => "${}",
696 TemplateHead => "${",
697 TemplateMiddle => "${expr}",
698 TemplateTail => "}",
699 PrivateIdentifier => "#identifier",
700 JSXText => "jsx",
701 At => "@",
702 Assert => "assert",
703 Any => "any",
704 Boolean => "boolean",
705 Constructor => "constructor",
706 Infer => "infer",
707 Intrinsic => "intrinsic",
708 Is => "is",
709 KeyOf => "keyof",
710 Module => "module",
711 Namespace => "namaespace",
712 Never => "never",
713 Out => "out",
714 Require => "require",
715 Number => "number",
716 Object => "object",
717 Satisfies => "satisfies",
718 Symbol => "symbol",
719 Undefined => "undefined",
720 Unique => "unique",
721 Unknown => "unknown",
722 Global => "global",
723 BigInt => "bigint",
724 }
725 }
726}
727
728impl Display for Kind {
729 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
730 self.to_str().fmt(f)
731 }
732}