1use crate::{ast::*, numbers::*, util::*, SyntaxText, TextRange, TextSize, TokenSet, T};
4use SyntaxKind::*;
5
6impl BracketExpr {
7 pub fn object(&self) -> Option<Expr> {
8 support::children(self.syntax()).next()
9 }
10
11 pub fn prop(&self) -> Option<Expr> {
12 support::children(self.syntax()).nth(1)
13 }
14}
15
16impl CondExpr {
17 pub fn test(&self) -> Option<Expr> {
18 support::children(self.syntax()).next()
19 }
20
21 pub fn cons(&self) -> Option<Expr> {
22 support::children(self.syntax()).nth(1)
23 }
24
25 pub fn alt(&self) -> Option<Expr> {
26 support::children(self.syntax()).nth(2)
27 }
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, Hash)]
31pub enum PropName {
32 Computed(ComputedPropertyName),
33 Literal(Literal),
34 Ident(Name),
35}
36
37impl AstNode for PropName {
38 fn can_cast(kind: SyntaxKind) -> bool {
39 matches!(kind, NAME | LITERAL | COMPUTED_PROPERTY_NAME)
40 }
41
42 fn cast(syntax: SyntaxNode) -> Option<Self> {
43 if !Self::can_cast(syntax.kind()) {
44 None
45 } else {
46 Some(match syntax.kind() {
47 LITERAL => PropName::Literal(Literal::cast(syntax).unwrap()),
48 NAME => PropName::Ident(Name::cast(syntax).unwrap()),
49 COMPUTED_PROPERTY_NAME => {
50 PropName::Computed(ComputedPropertyName::cast(syntax).unwrap())
51 }
52 _ => unreachable!(),
53 })
54 }
55 }
56
57 fn syntax(&self) -> &SyntaxNode {
58 match self {
59 PropName::Ident(s) => s.syntax(),
60 PropName::Literal(s) => s.syntax(),
61 PropName::Computed(s) => s.syntax(),
62 }
63 }
64}
65
66impl PropName {
67 pub fn as_string(&self) -> Option<std::string::String> {
68 Some(self.syntax().text().to_string())
69 }
70}
71
72impl LiteralProp {
73 pub fn key(&self) -> Option<PropName> {
74 if PropName::can_cast(
75 support::children::<PropName>(self.syntax())
76 .next()?
77 .syntax()
78 .kind(),
79 ) {
80 PropName::cast(
81 support::children::<PropName>(self.syntax())
82 .next()
83 .unwrap()
84 .syntax()
85 .to_owned(),
86 )
87 } else {
88 None
89 }
90 }
91
92 pub fn value(&self) -> Option<Expr> {
93 self.syntax().children().nth(1)?.try_to()
94 }
95}
96
97#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
99pub enum BinOp {
100 LessThan,
102 GreaterThan,
104 LessThanOrEqual,
106 GreaterThanOrEqual,
108 Equality,
110 StrictEquality,
112 Inequality,
114 StrictInequality,
116 Plus,
118 Minus,
120 Times,
122 Divide,
124 Remainder,
126 Exponent,
128 LeftShift,
130 RightShift,
132 UnsignedRightShift,
134 BitwiseAnd,
136 BitwiseOr,
138 BitwiseXor,
140 NullishCoalescing,
142 LogicalOr,
144 LogicalAnd,
146 In,
148 Instanceof,
150}
151
152impl BinExpr {
153 pub fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
154 self.syntax()
155 .children_with_tokens()
156 .filter_map(|x| x.into_token())
157 .find_map(|t| {
158 let op = match t.kind() {
159 T![<] => BinOp::LessThan,
160 T![>] => BinOp::GreaterThan,
161 T![<=] => BinOp::LessThanOrEqual,
162 T![>=] => BinOp::GreaterThanOrEqual,
163 T![==] => BinOp::Equality,
164 T![===] => BinOp::StrictEquality,
165 T![!=] => BinOp::Inequality,
166 T![!==] => BinOp::StrictInequality,
167 T![+] => BinOp::Plus,
168 T![-] => BinOp::Minus,
169 T![*] => BinOp::Times,
170 T![/] => BinOp::Divide,
171 T![%] => BinOp::Remainder,
172 T![**] => BinOp::Exponent,
173 T![<<] => BinOp::LeftShift,
174 T![>>] => BinOp::RightShift,
175 T![>>>] => BinOp::UnsignedRightShift,
176 T![&] => BinOp::BitwiseAnd,
177 T![|] => BinOp::BitwiseOr,
178 T![^] => BinOp::BitwiseXor,
179 T![??] => BinOp::NullishCoalescing,
180 T![||] => BinOp::LogicalOr,
181 T![&&] => BinOp::LogicalAnd,
182 T![in] => BinOp::In,
183 T![instanceof] => BinOp::Instanceof,
184 _ => return None,
185 };
186 Some((t, op))
187 })
188 }
189
190 pub fn op(&self) -> Option<BinOp> {
191 self.op_details().map(|t| t.1)
192 }
193
194 pub fn op_token(&self) -> Option<SyntaxToken> {
195 self.op_details().map(|t| t.0)
196 }
197
198 pub fn lhs(&self) -> Option<Expr> {
199 support::children(self.syntax()).next()
200 }
201
202 pub fn rhs(&self) -> Option<Expr> {
203 support::children(self.syntax()).nth(1)
204 }
205
206 pub fn conditional(&self) -> bool {
208 token_set![T![||], T![&&]].contains(self.op_token().map(|x| x.kind()).unwrap_or(T![&]))
209 }
210
211 pub fn comparison(&self) -> bool {
213 const SET: TokenSet = token_set![
214 T![>],
215 T![<],
216 T![>=],
217 T![<=],
218 T![==],
219 T![===],
220 T![!=],
221 T![!==]
222 ];
223 SET.contains(self.op_token().map(|x| x.kind()).unwrap_or(T![&]))
224 }
225}
226
227#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
228pub enum UnaryOp {
229 Increment,
231 Decrement,
233 Delete,
235 Void,
237 Typeof,
239 Plus,
241 Minus,
243 BitwiseNot,
245 LogicalNot,
247 Await,
249}
250
251impl UnaryExpr {
252 pub fn op_details(&self) -> Option<(SyntaxToken, UnaryOp)> {
253 self.syntax()
254 .children_with_tokens()
255 .filter_map(|x| x.into_token())
256 .find_map(|t| {
257 let op = match t.kind() {
258 T![++] => UnaryOp::Increment,
259 T![--] => UnaryOp::Decrement,
260 T![delete] => UnaryOp::Delete,
261 T![void] => UnaryOp::Void,
262 T![typeof] => UnaryOp::Typeof,
263 T![+] => UnaryOp::Plus,
264 T![-] => UnaryOp::Minus,
265 T![~] => UnaryOp::BitwiseNot,
266 T![!] => UnaryOp::LogicalNot,
267 T![await] => UnaryOp::Await,
268 _ => return None,
269 };
270 Some((t, op))
271 })
272 }
273
274 pub fn op(&self) -> Option<UnaryOp> {
275 self.op_details().map(|t| t.1)
276 }
277
278 pub fn op_token(&self) -> Option<SyntaxToken> {
279 self.op_details().map(|t| t.0)
280 }
281
282 pub fn is_update(&self) -> bool {
284 self.op().map_or(false, |op| {
285 op == UnaryOp::Increment || op == UnaryOp::Decrement
286 })
287 }
288
289 pub fn is_prefix(&self) -> Option<bool> {
291 if !self.is_update() {
292 return None;
293 }
294
295 Some(self.op_token()?.text_range().start() > self.expr()?.syntax().text_range().end())
296 }
297}
298
299impl KeyValuePattern {
300 pub fn value(&self) -> Option<Pattern> {
301 if self.syntax().children().count() == 2 {
303 Pattern::cast(self.syntax().last_child().unwrap())
304 } else {
305 self.colon_token()?
306 .next_sibling_or_token()?
307 .into_node()?
308 .try_to::<Pattern>()
309 }
310 }
311}
312
313#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
314pub enum AssignOp {
315 Assign,
316 AddAssign,
317 SubtractAssign,
318 TimesAssign,
319 RemainderAssign,
320 ExponentAssign,
321 LeftShiftAssign,
322 RightShiftAssign,
323 UnsignedRightShiftAssign,
324 BitwiseAndAssign,
325 BitwiseOrAssign,
326 BitwiseXorAssign,
327 LogicalAndAssign,
328 LogicalOrAssign,
329 NullishCoalescingAssign,
330}
331
332impl AssignExpr {
333 pub fn op_details(&self) -> Option<(SyntaxToken, AssignOp)> {
334 self.syntax()
335 .children_with_tokens()
336 .filter_map(|x| x.into_token())
337 .find_map(|t| {
338 let op = match t.kind() {
339 T![=] => AssignOp::Assign,
340 T![+=] => AssignOp::AddAssign,
341 T![-=] => AssignOp::SubtractAssign,
342 T![*=] => AssignOp::TimesAssign,
343 T![%=] => AssignOp::RemainderAssign,
344 T![**=] => AssignOp::ExponentAssign,
345 T![>>=] => AssignOp::LeftShiftAssign,
346 T![<<=] => AssignOp::RightShiftAssign,
347 T![>>>=] => AssignOp::UnsignedRightShiftAssign,
348 T![&=] => AssignOp::BitwiseAndAssign,
349 T![|=] => AssignOp::BitwiseOrAssign,
350 T![^=] => AssignOp::BitwiseXorAssign,
351 T![&&=] => AssignOp::LogicalAndAssign,
352 T![||=] => AssignOp::LogicalOrAssign,
353 T![??=] => AssignOp::NullishCoalescingAssign,
354 _ => return None,
355 };
356 Some((t, op))
357 })
358 }
359
360 pub fn op(&self) -> Option<AssignOp> {
361 self.op_details().map(|t| t.1)
362 }
363
364 pub fn op_token(&self) -> Option<SyntaxToken> {
365 self.op_details().map(|t| t.0)
366 }
367
368 pub fn lhs(&self) -> Option<PatternOrExpr> {
369 self.syntax.children().next().and_then(|n| n.try_to())
370 }
371
372 pub fn rhs(&self) -> Option<Expr> {
373 self.syntax.children().nth(1).and_then(|n| n.try_to())
374 }
375}
376
377impl ArrayExpr {
378 pub fn has_trailing_comma(&self) -> bool {
379 if let Some(last) = self.elements().last().map(|it| it.syntax().to_owned()) {
380 if let Some(tok) = last
381 .next_sibling_or_token()
382 .map(|it| it.into_token())
383 .flatten()
384 {
385 return tok.kind() == T![,];
386 }
387 }
388 false
389 }
390
391 pub fn sparse_elements(&self) -> Vec<SyntaxToken> {
393 let node = self.syntax();
394 let commas = node
395 .children_with_tokens()
396 .filter_map(|x| x.into_token().filter(|tok| tok.kind() == COMMA));
397 commas
398 .filter(|comma| {
399 let mut siblings = comma
400 .siblings_with_tokens(crate::Direction::Prev)
401 .skip(1)
402 .skip_while(|item| {
403 item.as_token()
404 .filter(|tok| tok.kind().is_trivia())
405 .is_some()
406 });
407
408 siblings
409 .next()
410 .and_then(|x| x.into_node()?.try_to::<ExprOrSpread>())
411 .is_none()
412 })
413 .collect()
414 }
415}
416
417#[derive(Debug, Clone, PartialEq, Eq, Hash)]
418pub enum ExprOrSpread {
419 Expr(Expr),
420 Spread(SpreadElement),
421}
422
423impl AstNode for ExprOrSpread {
424 fn can_cast(kind: SyntaxKind) -> bool {
425 match kind {
426 SPREAD_ELEMENT => true,
427 _ => Expr::can_cast(kind),
428 }
429 }
430
431 fn cast(syntax: SyntaxNode) -> Option<Self> {
432 if !Self::can_cast(syntax.kind()) {
433 None
434 } else {
435 Some(if syntax.kind() == SPREAD_ELEMENT {
436 ExprOrSpread::Spread(SpreadElement::cast(syntax).unwrap())
437 } else {
438 ExprOrSpread::Expr(Expr::cast(syntax).unwrap())
439 })
440 }
441 }
442
443 fn syntax(&self) -> &SyntaxNode {
444 match self {
445 ExprOrSpread::Expr(it) => it.syntax(),
446 ExprOrSpread::Spread(it) => it.syntax(),
447 }
448 }
449}
450
451impl ExprOrSpread {
452 pub fn is_spread(&self) -> bool {
453 matches!(self, ExprOrSpread::Spread(_))
454 }
455
456 pub fn is_expr(&self) -> bool {
457 matches!(self, ExprOrSpread::Expr(_))
458 }
459}
460
461impl ObjectExpr {
462 pub fn has_trailing_comma(&self) -> bool {
463 if let Some(last) = self.props().last().map(|it| it.syntax().to_owned()) {
464 if let Some(tok) = last
465 .next_sibling_or_token()
466 .map(|it| it.into_token())
467 .flatten()
468 {
469 return tok.kind() == T![,];
470 }
471 }
472 false
473 }
474}
475
476#[derive(Debug, Clone, PartialEq, PartialOrd)]
477pub enum LiteralKind {
478 Number(f64),
479 BigInt(BigInt),
480 String,
481 Null,
482 Bool(bool),
483 Regex,
484}
485
486impl Literal {
487 pub fn token(&self) -> SyntaxToken {
488 self.syntax()
489 .children_with_tokens()
490 .find(|e| !e.kind().is_trivia())
491 .and_then(|e| e.into_token())
492 .unwrap()
493 }
494
495 pub fn kind(&self) -> LiteralKind {
496 match self.token().kind() {
497 T![null] => LiteralKind::Null,
498 NUMBER => match parse_js_num(self.to_string()).unwrap() {
499 JsNum::BigInt(bigint) => LiteralKind::BigInt(bigint),
500 JsNum::Float(float) => LiteralKind::Number(float),
501 },
502 STRING => LiteralKind::String,
503 TRUE_KW => LiteralKind::Bool(true),
504 FALSE_KW => LiteralKind::Bool(false),
505 REGEX => LiteralKind::Regex,
506 _ => unreachable!(),
507 }
508 }
509
510 pub fn as_number(&self) -> Option<f64> {
511 if let LiteralKind::Number(num) = self.kind() {
512 Some(num)
513 } else {
514 None
515 }
516 }
517
518 pub fn is_number(&self) -> bool {
519 matches!(self.kind(), LiteralKind::Number(_))
520 }
521
522 pub fn is_string(&self) -> bool {
523 self.kind() == LiteralKind::String
524 }
525
526 pub fn is_null(&self) -> bool {
527 self.kind() == LiteralKind::Null
528 }
529
530 pub fn is_bool(&self) -> bool {
531 matches!(self.kind(), LiteralKind::Bool(_))
532 }
533
534 pub fn is_regex(&self) -> bool {
535 self.kind() == LiteralKind::Regex
536 }
537
538 pub fn inner_string_text(&self) -> Option<SyntaxText> {
540 if !self.is_string() {
541 return None;
542 }
543
544 let start = self.syntax().text_range().start() + TextSize::from(1);
545 let end_char = self
546 .syntax()
547 .text()
548 .char_at(self.syntax().text().len() - TextSize::from(1))
549 .unwrap();
550 let end = if end_char == '"' || end_char == '\'' {
551 self.syntax().text_range().end() - TextSize::from(1)
552 } else {
553 self.syntax().text_range().end()
554 };
555
556 let offset = self.syntax().text_range().start();
557
558 Some(
559 self.syntax()
560 .text()
561 .slice(TextRange::new(start - offset, end - offset)),
562 )
563 }
564}
565
566#[derive(Debug, Clone, PartialEq, Eq, Hash)]
567pub enum ExprOrBlock {
568 Expr(Expr),
569 Block(BlockStmt),
570}
571
572impl AstNode for ExprOrBlock {
573 fn can_cast(kind: SyntaxKind) -> bool {
574 if kind == BLOCK_STMT {
575 true
576 } else {
577 Expr::can_cast(kind)
578 }
579 }
580
581 fn cast(syntax: SyntaxNode) -> Option<Self> {
582 if syntax.kind() == BLOCK_STMT {
583 Some(ExprOrBlock::Block(BlockStmt::cast(syntax).unwrap()))
584 } else {
585 Some(ExprOrBlock::Expr(Expr::cast(syntax)?))
586 }
587 }
588
589 fn syntax(&self) -> &SyntaxNode {
590 match self {
591 ExprOrBlock::Expr(it) => it.syntax(),
592 ExprOrBlock::Block(it) => it.syntax(),
593 }
594 }
595}
596
597impl ArrowExpr {
598 pub fn body(&self) -> Option<ExprOrBlock> {
599 ExprOrBlock::cast(self.syntax().children().last()?)
600 }
601}
602
603#[derive(Debug, Clone, PartialEq, Eq, Hash)]
604pub enum PatternOrExpr {
605 Pattern(Pattern),
606 Expr(Expr),
607}
608
609impl AstNode for PatternOrExpr {
610 fn can_cast(kind: SyntaxKind) -> bool {
611 Expr::can_cast(kind) || Pattern::can_cast(kind)
612 }
613
614 fn cast(syntax: SyntaxNode) -> Option<Self> {
615 Some(if Pattern::can_cast(syntax.kind()) {
616 PatternOrExpr::Pattern(Pattern::cast(syntax).unwrap())
617 } else {
618 PatternOrExpr::Expr(Expr::cast(syntax).unwrap())
619 })
620 }
621
622 fn syntax(&self) -> &SyntaxNode {
623 match self {
624 PatternOrExpr::Pattern(it) => it.syntax(),
625 PatternOrExpr::Expr(it) => it.syntax(),
626 }
627 }
628}
629
630impl Template {
631 pub fn quasis(&self) -> impl Iterator<Item = SyntaxToken> {
635 self.syntax()
636 .children_with_tokens()
637 .filter_map(NodeOrToken::into_token)
638 .filter(|t| t.kind() == TEMPLATE_CHUNK)
639 }
640
641 pub fn template_range(&self) -> Option<TextRange> {
642 let start = self
643 .syntax()
644 .children_with_tokens()
645 .filter_map(|x| x.into_token())
646 .find(|tok| tok.kind() == BACKTICK)?;
647 Some(TextRange::new(
648 start.text_range().start(),
649 self.syntax().text_range().end(),
650 ))
651 }
652}
653
654impl ObjectProp {
655 pub fn key(&self) -> Option<std::string::String> {
656 Some(self.key_element()?.to_string())
657 }
658
659 pub fn key_element(&self) -> Option<SyntaxElement> {
660 Some(
661 match self {
662 ObjectProp::IdentProp(idt) => idt.syntax().clone(),
663 ObjectProp::LiteralProp(litprop) => prop_name_syntax(litprop.key()?)?,
664 ObjectProp::Getter(getter) => prop_name_syntax(getter.key()?)?,
665 ObjectProp::Setter(setter) => prop_name_syntax(setter.key()?)?,
666 ObjectProp::Method(method) => prop_name_syntax(method.name()?)?,
667 ObjectProp::InitializedProp(init) => init.key()?.syntax().clone(),
668 ObjectProp::SpreadProp(_) => return None,
669 }
670 .into(),
671 )
672 }
673}
674
675fn prop_name_syntax(name: PropName) -> Option<SyntaxNode> {
676 Some(match name {
677 PropName::Ident(idt) => idt.syntax().clone(),
678 PropName::Literal(lit) => lit.syntax().clone(),
679 PropName::Computed(_) => return None,
680 })
681}
682
683impl Expr {
684 pub fn opt_chain(&self) -> bool {
686 match self {
687 Expr::DotExpr(dotexpr) => dotexpr.opt_chain_token(),
688 Expr::CallExpr(callexpr) => callexpr.opt_chain_token(),
689 Expr::BracketExpr(bracketexpr) => bracketexpr.opt_chain_token(),
690 _ => return false,
691 }
692 .is_some()
693 }
694}
695
696impl DotExpr {
697 pub fn opt_chain_token(&self) -> Option<SyntaxToken> {
698 self.syntax()
699 .children_with_tokens()
700 .filter_map(|child| child.into_token())
701 .find(|tok| tok.kind() == QUESTIONDOT)
702 }
703}
704
705impl CallExpr {
706 pub fn opt_chain_token(&self) -> Option<SyntaxToken> {
707 self.syntax()
708 .children_with_tokens()
709 .filter_map(|child| child.into_token())
710 .find(|tok| tok.kind() == QUESTIONDOT)
711 }
712}
713
714impl BracketExpr {
715 pub fn opt_chain_token(&self) -> Option<SyntaxToken> {
716 self.syntax()
717 .children_with_tokens()
718 .filter_map(|child| child.into_token())
719 .find(|tok| tok.kind() == QUESTIONDOT)
720 }
721}
722
723#[macro_export]
725macro_rules! op {
726 (<) => {
727 $crate::ast::BinOp::LessThan
728 };
729 (>) => {
730 $crate::ast::BinOp::GreaterThan
731 };
732 (<=) => {
733 $crate::ast::BinOp::LessThanOrEqual
734 };
735 (>=) => {
736 $crate::ast::BinOp::GreaterThanOrEqual
737 };
738 (==) => {
739 $crate::ast::BinOp::Equality
740 };
741 (===) => {
742 $crate::ast::BinOp::StrictEquality
743 };
744 (!=) => {
745 $crate::ast::BinOp::Inequality
746 };
747 (!==) => {
748 $crate::ast::BinOp::StrictInequality
749 };
750 (+) => {
751 $crate::ast::BinOp::Plus
752 };
753 (-) => {
754 $crate::ast::BinOp::Minus
755 };
756 (*) => {
757 $crate::ast::BinOp::Times
758 };
759 (/) => {
760 $crate::ast::BinOp::Divide
761 };
762 (%) => {
763 $crate::ast::BinOp::Remainder
764 };
765 (**) => {
766 $crate::ast::BinOp::Exponent
767 };
768 (<<) => {
769 $crate::ast::BinOp::LeftShift
770 };
771 (>>) => {
772 $crate::ast::BinOp::RightShift
773 };
774 (>>>) => {
775 $crate::ast::BinOp::UnsignedRightShift
776 };
777 (&) => {
778 $crate::ast::BinOp::BitwiseAnd
779 };
780 (|) => {
781 $crate::ast::BinOp::BitwiseOr
782 };
783 (^) => {
784 $crate::ast::BinOp::BitwiseXor
785 };
786 (??) => {
787 $crate::ast::BinOp::NullishCoalescing
788 };
789 (||) => {
790 $crate::ast::BinOp::LogicalOr
791 };
792 (&&) => {
793 $crate::ast::BinOp::LogicalAnd
794 };
795 (in) => {
796 $crate::ast::BinOp::In
797 };
798 (instanceof) => {
799 $crate::ast::BinOp::Instanceof
800 };
801
802 (=) => {
803 $crate::ast::AssignOp::Assign
804 };
805 (+=) => {
806 $crate::ast::AssignOp::AddAssign
807 };
808 (-=) => {
809 $crate::ast::AssignOp::SubtractAssign
810 };
811 (*=) => {
812 $crate::ast::AssignOp::TimesAssign
813 };
814 (%=) => {
815 $crate::ast::AssignOp::RemainderAssign
816 };
817 (**=) => {
818 $crate::ast::AssignOp::ExponentAssign
819 };
820 (>>=) => {
821 $crate::ast::AssignOp::LeftShiftAssign
822 };
823 (<<=) => {
824 $crate::ast::AssignOp::RightShiftAssign
825 };
826 (>>>=) => {
827 $crate::ast::AssignOp::UnsignedRightShiftAssign
828 };
829 (&=) => {
830 $crate::ast::AssignOp::BitwiseAndAssign
831 };
832 (|=) => {
833 $crate::ast::AssignOp::BitwiseOrAssign
834 };
835 (^=) => {
836 $crate::ast::AssignOp::BitwiseXorAssign
837 };
838 (&&=) => {
839 $crate::ast::AssignOp::LogicalAndAssign
840 };
841 (||=) => {
842 $crate::ast::AssignOp::LogicalOrAssign
843 };
844 (??=) => {
845 $crate::ast::AssignOp::NullishCoalescingAssign
846 };
847
848 (++) => {
849 $crate::ast::UnaryOp::Increment
850 };
851 (--) => {
852 $crate::ast::UnaryOp::Decrement
853 };
854 (delete) => {
855 $crate::ast::UnaryOp::Delete
856 };
857 (void) => {
858 $crate::ast::UnaryOp::Void
859 };
860 (typeof) => {
861 $crate::ast::UnaryOp::Typeof
862 };
863 (+) => {
864 $crate::ast::UnaryOp::Plus
865 };
866 (-) => {
867 $crate::ast::UnaryOp::Minus
868 };
869 (~) => {
870 $crate::ast::UnaryOp::BitwiseNot
871 };
872 (!) => {
873 $crate::ast::UnaryOp::LogicalNot
874 };
875 (await) => {
876 $crate::ast::UnaryOp::Await
877 };
878}