1use oxc_allocator::CloneIn;
6use oxc_ast_macros::ast;
7use oxc_estree::ESTree;
8use oxc_span::ContentEq;
9
10use crate::precedence::{GetPrecedence, Precedence};
11
12#[ast]
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[generate_derive(CloneIn, ContentEq, ESTree)]
19pub enum AssignmentOperator {
20 #[estree(rename = "=")]
22 Assign = 0,
23 #[estree(rename = "+=")]
25 Addition = 1,
26 #[estree(rename = "-=")]
28 Subtraction = 2,
29 #[estree(rename = "*=")]
31 Multiplication = 3,
32 #[estree(rename = "/=")]
34 Division = 4,
35 #[estree(rename = "%=")]
37 Remainder = 5,
38 #[estree(rename = "**=")]
40 Exponential = 6,
41 #[estree(rename = "<<=")]
43 ShiftLeft = 7,
44 #[estree(rename = ">>=")]
46 ShiftRight = 8,
47 #[estree(rename = ">>>=")]
49 ShiftRightZeroFill = 9,
50 #[estree(rename = "|=")]
52 BitwiseOR = 10,
53 #[estree(rename = "^=")]
55 BitwiseXOR = 11,
56 #[estree(rename = "&=")]
58 BitwiseAnd = 12,
59 #[estree(rename = "||=")]
61 LogicalOr = 13,
62 #[estree(rename = "&&=")]
64 LogicalAnd = 14,
65 #[estree(rename = "??=")]
67 LogicalNullish = 15,
68}
69
70impl AssignmentOperator {
71 pub fn is_assign(self) -> bool {
73 self == Self::Assign
74 }
75
76 pub fn is_logical(self) -> bool {
78 matches!(self, Self::LogicalOr | Self::LogicalAnd | Self::LogicalNullish)
79 }
80
81 #[rustfmt::skip]
83 pub fn is_arithmetic(self) -> bool {
84 matches!(
85 self,
86 Self::Addition | Self::Subtraction | Self::Multiplication
87 | Self::Division | Self::Remainder | Self::Exponential
88 )
89 }
90
91 #[rustfmt::skip]
93 pub fn is_bitwise(self) -> bool {
94 matches!(
95 self,
96 Self::ShiftLeft | Self::ShiftRight | Self::ShiftRightZeroFill
97 | Self::BitwiseOR | Self::BitwiseXOR | Self::BitwiseAnd
98 )
99 }
100
101 pub fn to_logical_operator(self) -> Option<LogicalOperator> {
103 match self {
104 Self::LogicalOr => Some(LogicalOperator::Or),
105 Self::LogicalAnd => Some(LogicalOperator::And),
106 Self::LogicalNullish => Some(LogicalOperator::Coalesce),
107 _ => None,
108 }
109 }
110
111 pub fn to_binary_operator(self) -> Option<BinaryOperator> {
113 match self {
114 Self::Addition => Some(BinaryOperator::Addition),
115 Self::Subtraction => Some(BinaryOperator::Subtraction),
116 Self::Multiplication => Some(BinaryOperator::Multiplication),
117 Self::Division => Some(BinaryOperator::Division),
118 Self::Remainder => Some(BinaryOperator::Remainder),
119 Self::Exponential => Some(BinaryOperator::Exponential),
120 Self::ShiftLeft => Some(BinaryOperator::ShiftLeft),
121 Self::ShiftRight => Some(BinaryOperator::ShiftRight),
122 Self::ShiftRightZeroFill => Some(BinaryOperator::ShiftRightZeroFill),
123 Self::BitwiseOR => Some(BinaryOperator::BitwiseOR),
124 Self::BitwiseXOR => Some(BinaryOperator::BitwiseXOR),
125 Self::BitwiseAnd => Some(BinaryOperator::BitwiseAnd),
126 _ => None,
127 }
128 }
129
130 pub fn as_str(&self) -> &'static str {
134 match self {
135 Self::Assign => "=",
136 Self::Addition => "+=",
137 Self::Subtraction => "-=",
138 Self::Multiplication => "*=",
139 Self::Division => "/=",
140 Self::Remainder => "%=",
141 Self::Exponential => "**=",
142 Self::ShiftLeft => "<<=",
143 Self::ShiftRight => ">>=",
144 Self::ShiftRightZeroFill => ">>>=",
145 Self::BitwiseOR => "|=",
146 Self::BitwiseXOR => "^=",
147 Self::BitwiseAnd => "&=",
148 Self::LogicalOr => "||=",
149 Self::LogicalAnd => "&&=",
150 Self::LogicalNullish => "??=",
151 }
152 }
153}
154
155#[ast]
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
162#[generate_derive(CloneIn, ContentEq, ESTree)]
163pub enum BinaryOperator {
164 #[estree(rename = "==")]
166 Equality = 0,
167 #[estree(rename = "!=")]
169 Inequality = 1,
170 #[estree(rename = "===")]
172 StrictEquality = 2,
173 #[estree(rename = "!==")]
175 StrictInequality = 3,
176 #[estree(rename = "<")]
178 LessThan = 4,
179 #[estree(rename = "<=")]
181 LessEqualThan = 5,
182 #[estree(rename = ">")]
184 GreaterThan = 6,
185 #[estree(rename = ">=")]
187 GreaterEqualThan = 7,
188 #[estree(rename = "+")]
190 Addition = 8,
191 #[estree(rename = "-")]
193 Subtraction = 9,
194 #[estree(rename = "*")]
196 Multiplication = 10,
197 #[estree(rename = "/")]
199 Division = 11,
200 #[estree(rename = "%")]
202 Remainder = 12,
203 #[estree(rename = "**")]
205 Exponential = 13,
206 #[estree(rename = "<<")]
208 ShiftLeft = 14,
209 #[estree(rename = ">>")]
211 ShiftRight = 15,
212 #[estree(rename = ">>>")]
214 ShiftRightZeroFill = 16,
215 #[estree(rename = "|")]
217 BitwiseOR = 17,
218 #[estree(rename = "^")]
220 BitwiseXOR = 18,
221 #[estree(rename = "&")]
223 BitwiseAnd = 19,
224 #[estree(rename = "in")]
226 In = 20,
227 #[estree(rename = "instanceof")]
229 Instanceof = 21,
230}
231
232impl BinaryOperator {
233 #[rustfmt::skip]
235 pub fn is_equality(self) -> bool {
236 matches!(self, Self::Equality | Self::Inequality | Self::StrictEquality | Self::StrictInequality)
237 }
238
239 #[rustfmt::skip]
241 pub fn is_compare(self) -> bool {
242 matches!(self, Self::LessThan | Self::LessEqualThan | Self::GreaterThan | Self::GreaterEqualThan)
243 }
244
245 #[rustfmt::skip]
247 pub fn is_arithmetic(self) -> bool {
248 matches!(
249 self,
250 Self::Addition | Self::Subtraction | Self::Multiplication
251 | Self::Division | Self::Remainder | Self::Exponential
252 )
253 }
254
255 pub fn is_multiplicative(self) -> bool {
258 matches!(self, Self::Multiplication | Self::Division | Self::Remainder)
259 }
260
261 pub fn is_relational(self) -> bool {
263 matches!(self, Self::In | Self::Instanceof)
264 }
265
266 pub fn is_in(self) -> bool {
268 self == Self::In
269 }
270
271 pub fn is_instance_of(self) -> bool {
273 self == Self::Instanceof
274 }
275
276 #[rustfmt::skip]
278 pub fn is_bitwise(self) -> bool {
279 self.is_bitshift() || matches!(self, Self::BitwiseOR | Self::BitwiseXOR | Self::BitwiseAnd)
280 }
281
282 pub fn is_bitshift(self) -> bool {
284 matches!(self, Self::ShiftLeft | Self::ShiftRight | Self::ShiftRightZeroFill)
285 }
286
287 pub fn is_numeric_or_string_binary_operator(self) -> bool {
289 self.is_arithmetic() || self.is_bitwise()
290 }
291
292 pub fn is_keyword(self) -> bool {
294 matches!(self, Self::In | Self::Instanceof)
295 }
296
297 pub fn compare_inverse_operator(self) -> Option<Self> {
300 match self {
301 Self::LessThan => Some(Self::GreaterThan),
302 Self::LessEqualThan => Some(Self::GreaterEqualThan),
303 Self::GreaterThan => Some(Self::LessThan),
304 Self::GreaterEqualThan => Some(Self::LessEqualThan),
305 _ => None,
306 }
307 }
308
309 pub fn equality_inverse_operator(self) -> Option<Self> {
312 match self {
313 Self::Equality => Some(Self::Inequality),
314 Self::Inequality => Some(Self::Equality),
315 Self::StrictEquality => Some(Self::StrictInequality),
316 Self::StrictInequality => Some(Self::StrictEquality),
317 _ => None,
318 }
319 }
320
321 pub fn to_assignment_operator(self) -> Option<AssignmentOperator> {
323 match self {
324 Self::Addition => Some(AssignmentOperator::Addition),
325 Self::Subtraction => Some(AssignmentOperator::Subtraction),
326 Self::Multiplication => Some(AssignmentOperator::Multiplication),
327 Self::Division => Some(AssignmentOperator::Division),
328 Self::Remainder => Some(AssignmentOperator::Remainder),
329 Self::Exponential => Some(AssignmentOperator::Exponential),
330 Self::ShiftLeft => Some(AssignmentOperator::ShiftLeft),
331 Self::ShiftRight => Some(AssignmentOperator::ShiftRight),
332 Self::ShiftRightZeroFill => Some(AssignmentOperator::ShiftRightZeroFill),
333 Self::BitwiseOR => Some(AssignmentOperator::BitwiseOR),
334 Self::BitwiseXOR => Some(AssignmentOperator::BitwiseXOR),
335 Self::BitwiseAnd => Some(AssignmentOperator::BitwiseAnd),
336 _ => None,
337 }
338 }
339
340 pub fn as_str(&self) -> &'static str {
342 match self {
343 Self::Equality => "==",
344 Self::Inequality => "!=",
345 Self::StrictEquality => "===",
346 Self::StrictInequality => "!==",
347 Self::LessThan => "<",
348 Self::LessEqualThan => "<=",
349 Self::GreaterThan => ">",
350 Self::GreaterEqualThan => ">=",
351 Self::Addition => "+",
352 Self::Subtraction => "-",
353 Self::Multiplication => "*",
354 Self::Division => "/",
355 Self::Remainder => "%",
356 Self::Exponential => "**",
357 Self::ShiftLeft => "<<",
358 Self::ShiftRight => ">>",
359 Self::ShiftRightZeroFill => ">>>",
360 Self::BitwiseOR => "|",
361 Self::BitwiseXOR => "^",
362 Self::BitwiseAnd => "&",
363 Self::In => "in",
364 Self::Instanceof => "instanceof",
365 }
366 }
367
368 pub fn lower_precedence(&self) -> Precedence {
372 match self {
373 Self::BitwiseOR => Precedence::LogicalAnd,
374 Self::BitwiseXOR => Precedence::BitwiseOr,
375 Self::BitwiseAnd => Precedence::BitwiseXor,
376 Self::Equality | Self::Inequality | Self::StrictEquality | Self::StrictInequality => {
377 Precedence::BitwiseAnd
378 }
379 Self::LessThan
380 | Self::LessEqualThan
381 | Self::GreaterThan
382 | Self::GreaterEqualThan
383 | Self::Instanceof
384 | Self::In => Precedence::Equals,
385 Self::ShiftLeft | Self::ShiftRight | Self::ShiftRightZeroFill => Precedence::Compare,
386 Self::Addition | Self::Subtraction => Precedence::Shift,
387 Self::Multiplication | Self::Remainder | Self::Division => Precedence::Add,
388 Self::Exponential => Precedence::Multiply,
389 }
390 }
391}
392
393impl GetPrecedence for BinaryOperator {
394 fn precedence(&self) -> Precedence {
395 match self {
396 Self::BitwiseOR => Precedence::BitwiseOr,
397 Self::BitwiseXOR => Precedence::BitwiseXor,
398 Self::BitwiseAnd => Precedence::BitwiseAnd,
399 Self::Equality | Self::Inequality | Self::StrictEquality | Self::StrictInequality => {
400 Precedence::Equals
401 }
402 Self::LessThan
403 | Self::LessEqualThan
404 | Self::GreaterThan
405 | Self::GreaterEqualThan
406 | Self::Instanceof
407 | Self::In => Precedence::Compare,
408 Self::ShiftLeft | Self::ShiftRight | Self::ShiftRightZeroFill => Precedence::Shift,
409 Self::Subtraction | Self::Addition => Precedence::Add,
410 Self::Multiplication | Self::Remainder | Self::Division => Precedence::Multiply,
411 Self::Exponential => Precedence::Exponentiation,
412 }
413 }
414}
415
416#[ast]
418#[derive(Debug, Clone, Copy, PartialEq, Eq)]
419#[generate_derive(CloneIn, ContentEq, ESTree)]
420pub enum LogicalOperator {
421 #[estree(rename = "||")]
423 Or = 0,
424 #[estree(rename = "&&")]
426 And = 1,
427 #[estree(rename = "??")]
429 Coalesce = 2,
430}
431
432impl LogicalOperator {
433 #[inline]
435 pub fn is_or(self) -> bool {
436 self == Self::Or
437 }
438
439 #[inline]
441 pub fn is_and(self) -> bool {
442 self == Self::And
443 }
444
445 #[inline]
447 pub fn is_coalesce(self) -> bool {
448 self == Self::Coalesce
449 }
450
451 pub fn as_str(&self) -> &'static str {
453 match self {
454 Self::Or => "||",
455 Self::And => "&&",
456 Self::Coalesce => "??",
457 }
458 }
459
460 pub fn lower_precedence(&self) -> Precedence {
464 match self {
465 Self::Or => Precedence::NullishCoalescing,
466 Self::And => Precedence::LogicalOr,
467 Self::Coalesce => Precedence::Conditional,
468 }
469 }
470
471 pub fn to_assignment_operator(self) -> AssignmentOperator {
473 match self {
474 Self::Or => AssignmentOperator::LogicalOr,
475 Self::And => AssignmentOperator::LogicalAnd,
476 Self::Coalesce => AssignmentOperator::LogicalNullish,
477 }
478 }
479}
480
481impl GetPrecedence for LogicalOperator {
482 fn precedence(&self) -> Precedence {
483 match self {
484 Self::Or => Precedence::LogicalOr,
485 Self::And => Precedence::LogicalAnd,
486 Self::Coalesce => Precedence::NullishCoalescing,
487 }
488 }
489}
490
491#[ast]
498#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
499#[generate_derive(CloneIn, ContentEq, ESTree)]
500pub enum UnaryOperator {
501 #[estree(rename = "+")]
503 UnaryPlus = 0,
504 #[estree(rename = "-")]
506 UnaryNegation = 1,
507 #[estree(rename = "!")]
509 LogicalNot = 2,
510 #[estree(rename = "~")]
512 BitwiseNot = 3,
513 #[estree(rename = "typeof")]
515 Typeof = 4,
516 #[estree(rename = "void")]
518 Void = 5,
519 #[estree(rename = "delete")]
521 Delete = 6,
522}
523
524impl UnaryOperator {
525 pub fn is_arithmetic(self) -> bool {
527 matches!(self, Self::UnaryPlus | Self::UnaryNegation)
528 }
529
530 pub fn is_not(self) -> bool {
534 self == Self::LogicalNot
535 }
536
537 pub fn is_bitwise(self) -> bool {
539 self == Self::BitwiseNot
540 }
541
542 pub fn is_typeof(self) -> bool {
544 self == Self::Typeof
545 }
546
547 pub fn is_void(self) -> bool {
549 self == Self::Void
550 }
551
552 pub fn is_delete(self) -> bool {
554 self == Self::Delete
555 }
556
557 pub fn is_keyword(self) -> bool {
559 matches!(self, Self::Typeof | Self::Void | Self::Delete)
560 }
561
562 pub fn as_str(&self) -> &'static str {
564 match self {
565 Self::UnaryPlus => "+",
566 Self::UnaryNegation => "-",
567 Self::LogicalNot => "!",
568 Self::BitwiseNot => "~",
569 Self::Typeof => "typeof",
570 Self::Void => "void",
571 Self::Delete => "delete",
572 }
573 }
574}
575
576#[ast]
578#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
579#[generate_derive(CloneIn, ContentEq, ESTree)]
580pub enum UpdateOperator {
581 #[estree(rename = "++")]
583 Increment = 0,
584 #[estree(rename = "--")]
586 Decrement = 1,
587}
588
589impl UpdateOperator {
590 pub fn as_str(&self) -> &'static str {
592 match self {
593 Self::Increment => "++",
594 Self::Decrement => "--",
595 }
596 }
597}