boa_ast/expression/operator/binary/op.rs
1//! This module implements various structure for logic handling.
2
3use std::fmt::{Display, Formatter, Result};
4
5/// This represents a binary operation between two values.
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub enum BinaryOp {
10 /// Numeric operation.
11 ///
12 /// see: [`NumOp`](enum.NumOp.html)
13 Arithmetic(ArithmeticOp),
14
15 /// Bitwise operation.
16 ///
17 /// see: [`BitOp`](enum.BitOp.html).
18 Bitwise(BitwiseOp),
19
20 /// Comparative operation.
21 ///
22 /// see: [`CompOp`](enum.CompOp.html).
23 Relational(RelationalOp),
24
25 /// Logical operation.
26 ///
27 /// see: [`LogOp`](enum.LogOp.html).
28 Logical(LogicalOp),
29
30 /// Comma operation.
31 Comma,
32}
33
34impl From<ArithmeticOp> for BinaryOp {
35 #[inline]
36 fn from(op: ArithmeticOp) -> Self {
37 Self::Arithmetic(op)
38 }
39}
40
41impl From<BitwiseOp> for BinaryOp {
42 #[inline]
43 fn from(op: BitwiseOp) -> Self {
44 Self::Bitwise(op)
45 }
46}
47
48impl From<RelationalOp> for BinaryOp {
49 #[inline]
50 fn from(op: RelationalOp) -> Self {
51 Self::Relational(op)
52 }
53}
54
55impl From<LogicalOp> for BinaryOp {
56 #[inline]
57 fn from(op: LogicalOp) -> Self {
58 Self::Logical(op)
59 }
60}
61
62impl BinaryOp {
63 /// Retrieves the operation as a static string.
64 const fn as_str(self) -> &'static str {
65 match self {
66 Self::Arithmetic(ref op) => op.as_str(),
67 Self::Bitwise(ref op) => op.as_str(),
68 Self::Relational(ref op) => op.as_str(),
69 Self::Logical(ref op) => op.as_str(),
70 Self::Comma => ",",
71 }
72 }
73}
74
75impl Display for BinaryOp {
76 #[inline]
77 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
78 write!(f, "{}", self.as_str())
79 }
80}
81
82/// Arithmetic operators take numerical values (either literals or variables)
83/// as their operands and return a single numerical value.
84///
85/// More information:
86/// - [MDN documentation][mdn]
87///
88/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Arithmetic
89#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
90#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
91#[derive(Clone, Copy, Debug, PartialEq, Eq)]
92pub enum ArithmeticOp {
93 /// The addition operator produces the sum of numeric operands or string concatenation.
94 ///
95 /// Syntax: `x + y`
96 ///
97 /// More information:
98 /// - [ECMAScript reference][spec].
99 /// - [MDN documentation][mdn]
100 ///
101 /// [spec]: https://tc39.es/ecma262/#sec-addition-operator-plus
102 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Addition
103 Add,
104
105 /// The subtraction operator subtracts the two operands, producing their difference.
106 ///
107 /// Syntax: `x - y`
108 ///
109 /// More information:
110 /// - [ECMAScript reference][spec].
111 /// - [MDN documentation][mdn]
112 ///
113 /// [spec]: https://tc39.es/ecma262/#sec-subtraction-operator-minus
114 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Subtraction
115 Sub,
116
117 /// The division operator produces the quotient of its operands where the left operand
118 /// is the dividend and the right operand is the divisor.
119 ///
120 /// Syntax: `x / y`
121 ///
122 /// More information:
123 /// - [ECMAScript reference][spec]
124 /// - [MDN documentation][mdn]
125 ///
126 /// [spec]: https://tc39.es/ecma262/#prod-MultiplicativeOperator
127 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Division
128 Div,
129
130 /// The multiplication operator produces the product of the operands.
131 ///
132 /// Syntax: `x * y`
133 ///
134 /// More information:
135 /// - [ECMAScript reference][spec]
136 /// - [MDN documentation][mdn]
137 ///
138 /// [spec]: https://tc39.es/ecma262/#prod-MultiplicativeExpression
139 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Multiplication
140 Mul,
141
142 /// The exponentiation operator returns the result of raising the first operand to
143 /// the power of the second operand.
144 ///
145 /// Syntax: `x ** y`
146 ///
147 /// The exponentiation operator is right-associative. a ** b ** c is equal to a ** (b ** c).
148 ///
149 /// More information:
150 /// - [ECMAScript reference][spec]
151 /// - [MDN documentation][mdn]
152 ///
153 /// [spec]: https://tc39.es/ecma262/#sec-exp-operator
154 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Exponentiation
155 Exp,
156
157 /// The remainder operator returns the remainder left over when one operand is divided by a second operand.
158 ///
159 /// Syntax: `x % y`
160 ///
161 /// The remainder operator always takes the sign of the dividend.
162 ///
163 /// More information:
164 /// - [ECMAScript reference][spec]
165 /// - [MDN documentation][mdn]
166 ///
167 /// [spec]: https://tc39.es/ecma262/#prod-MultiplicativeOperator
168 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Remainder
169 Mod,
170}
171
172impl ArithmeticOp {
173 /// Retrieves the operation as a static string.
174 const fn as_str(self) -> &'static str {
175 match self {
176 Self::Add => "+",
177 Self::Sub => "-",
178 Self::Div => "/",
179 Self::Mul => "*",
180 Self::Exp => "**",
181 Self::Mod => "%",
182 }
183 }
184}
185
186impl Display for ArithmeticOp {
187 #[inline]
188 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
189 write!(f, "{}", self.as_str())
190 }
191}
192
193/// A bitwise operator is an operator used to perform bitwise operations
194/// on bit patterns or binary numerals that involve the manipulation of individual bits.
195///
196/// More information:
197/// - [MDN documentation][mdn]
198///
199/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise
200#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
201#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
202#[derive(Clone, Copy, Debug, PartialEq, Eq)]
203pub enum BitwiseOp {
204 /// Performs the AND operation on each pair of bits. a AND b yields 1 only if both a and b are 1.
205 ///
206 /// Syntax: `x & y`
207 ///
208 /// More information:
209 /// - [ECMAScript reference][spec]
210 /// - [MDN documentation][mdn]
211 ///
212 /// [spec]: https://tc39.es/ecma262/#prod-BitwiseANDExpression
213 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_AND
214 And,
215
216 /// Performs the OR operation on each pair of bits. a OR b yields 1 if either a or b is 1.
217 ///
218 /// Syntax: `x | y`
219 ///
220 /// More information:
221 /// - [ECMAScript reference][spec]
222 /// - [MDN documentation][mdn]
223 ///
224 /// [spec]: https://tc39.es/ecma262/#prod-BitwiseORExpression
225 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_OR
226 Or,
227
228 /// Performs the XOR operation on each pair of bits. a XOR b yields 1 if a and b are different.
229 ///
230 /// Syntax: `x ^ y`
231 ///
232 /// More information:
233 /// - [ECMAScript reference][spec]
234 /// - [MDN documentation][mdn]
235 ///
236 /// [spec]: https://tc39.es/ecma262/#prod-BitwiseXORExpression
237 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_XOR
238 Xor,
239
240 /// This operator shifts the first operand the specified number of bits to the left.
241 ///
242 /// Syntax: `x << y`
243 ///
244 /// Excess bits shifted off to the left are discarded. Zero bits are shifted in from the right.
245 ///
246 /// More information:
247 /// - [ECMAScript reference][spec]
248 /// - [MDN documentation][mdn]
249 ///
250 /// [spec]: https://tc39.es/ecma262/#sec-left-shift-operator
251 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Left_shift
252 Shl,
253
254 /// This operator shifts the first operand the specified number of bits to the right.
255 ///
256 /// Syntax: `x >> y`
257 ///
258 /// Excess bits shifted off to the right are discarded. Copies of the leftmost bit
259 /// are shifted in from the left. Since the new leftmost bit has the same value as
260 /// the previous leftmost bit, the sign bit (the leftmost bit) does not change.
261 /// Hence the name "sign-propagating".
262 ///
263 /// More information:
264 /// - [ECMAScript reference][spec]
265 /// - [MDN documentation][mdn]
266 ///
267 /// [spec]: https://tc39.es/ecma262/#sec-signed-right-shift-operator
268 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Right_shift
269 Shr,
270
271 /// This operator shifts the first operand the specified number of bits to the right.
272 ///
273 /// Syntax: `x >>> y`
274 ///
275 /// Excess bits shifted off to the right are discarded. Zero bits are shifted in
276 /// from the left. The sign bit becomes 0, so the result is always non-negative.
277 /// Unlike the other bitwise operators, zero-fill right shift returns an unsigned 32-bit integer.
278 ///
279 /// More information:
280 /// - [ECMAScript reference][spec]
281 /// - [MDN documentation][mdn]
282 ///
283 /// [spec]: https://tc39.es/ecma262/#sec-unsigned-right-shift-operator
284 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Unsigned_right_shift
285 UShr,
286}
287
288impl BitwiseOp {
289 /// Retrieves the operation as a static string.
290 const fn as_str(self) -> &'static str {
291 match self {
292 Self::And => "&",
293 Self::Or => "|",
294 Self::Xor => "^",
295 Self::Shl => "<<",
296 Self::Shr => ">>",
297 Self::UShr => ">>>",
298 }
299 }
300}
301
302impl Display for BitwiseOp {
303 #[inline]
304 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
305 write!(f, "{}", self.as_str())
306 }
307}
308
309/// A relational operator compares its operands and returns a logical value based on whether the relation is true.
310///
311/// The operands can be numerical, string, logical, or object values. Strings are compared based on standard
312/// lexicographical ordering, using Unicode values. In most cases, if the two operands are not of the same type,
313/// JavaScript attempts to convert them to an appropriate type for the comparison. This behavior generally results in
314/// comparing the operands numerically. The sole exceptions to type conversion within comparisons involve the `===` and `!==`
315/// operators, which perform strict equality and inequality comparisons. These operators do not attempt to convert the operands
316/// to compatible types before checking equality.
317///
318/// More information:
319/// - [ECMAScript reference][spec]
320/// - [MDN documentation][mdn]
321///
322/// [spec]: tc39.es/ecma262/#sec-testing-and-comparison-operations
323/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Comparison
324#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
325#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
326#[derive(Clone, Copy, Debug, PartialEq, Eq)]
327pub enum RelationalOp {
328 /// The equality operator converts the operands if they are not of the same type, then applies
329 /// strict comparison.
330 ///
331 /// Syntax: `y == y`
332 ///
333 /// If both operands are objects, then JavaScript compares internal references which are equal
334 /// when operands refer to the same object in memory.
335 ///
336 /// More information:
337 /// - [ECMAScript reference][spec]
338 /// - [MDN documentation][mdn]
339 ///
340 /// [spec]: https://tc39.es/ecma262/#sec-abstract-equality-comparison
341 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Equality
342 Equal,
343
344 /// The inequality operator returns `true` if the operands are not equal.
345 ///
346 /// Syntax: `x != y`
347 ///
348 /// If the two operands are not of the same type, JavaScript attempts to convert the operands
349 /// to an appropriate type for the comparison. If both operands are objects, then JavaScript
350 /// compares internal references which are not equal when operands refer to different objects
351 /// in memory.
352 ///
353 /// More information:
354 /// - [ECMAScript reference][spec]
355 /// - [MDN documentation][mdn]
356 ///
357 /// [spec]: https://tc39.es/ecma262/#prod-EqualityExpression
358 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Inequality
359 NotEqual,
360
361 /// The identity operator returns `true` if the operands are strictly equal **with no type
362 /// conversion**.
363 ///
364 /// Syntax: `x === y`
365 ///
366 /// Returns `true` if the operands are equal and of the same type.
367 ///
368 /// More information:
369 /// - [ECMAScript reference][spec]
370 /// - [MDN documentation][mdn]
371 ///
372 /// [spec]: https://tc39.es/ecma262/#sec-strict-equality-comparison
373 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Identity
374 StrictEqual,
375
376 /// The non-identity operator returns `true` if the operands **are not equal and/or not of the
377 /// same type**.
378 ///
379 /// Syntax: `x !== y`
380 ///
381 /// Returns `true` if the operands are of the same type but not equal, or are of different type.
382 ///
383 /// More information:
384 /// - [ECMAScript reference][spec]
385 /// - [MDN documentation][mdn]
386 ///
387 /// [spec]: https://tc39.es/ecma262/#prod-EqualityExpression
388 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Nonidentity>
389 StrictNotEqual,
390
391 /// The greater than operator returns `true` if the left operand is greater than the right
392 /// operand.
393 ///
394 /// Syntax: `x > y`
395 ///
396 /// Returns `true` if the left operand is greater than the right operand.
397 ///
398 /// More information:
399 /// - [ECMAScript reference][spec]
400 /// - [MDN documentation][mdn]
401 ///
402 /// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
403 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Greater_than_operator
404 GreaterThan,
405
406 /// The greater than or equal operator returns `true` if the left operand is greater than or
407 /// equal to the right operand.
408 ///
409 /// Syntax: `x >= y`
410 ///
411 /// Returns `true` if the left operand is greater than the right operand.
412 ///
413 /// More information:
414 /// - [ECMAScript reference][spec]
415 /// - [MDN documentation][mdn]
416 ///
417 /// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
418 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Greater_than_operator
419 GreaterThanOrEqual,
420
421 /// The less than operator returns `true` if the left operand is less than the right operand.
422 ///
423 /// Syntax: `x < y`
424 ///
425 /// Returns `true` if the left operand is less than the right operand.
426 ///
427 /// More information:
428 /// - [ECMAScript reference][spec]
429 /// - [MDN documentation][mdn]
430 ///
431 /// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
432 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Less_than_operator
433 LessThan,
434
435 /// The less than or equal operator returns `true` if the left operand is less than or equal to
436 /// the right operand.
437 ///
438 /// Syntax: `x <= y`
439 ///
440 /// Returns `true` if the left operand is less than or equal to the right operand.
441 ///
442 /// More information:
443 /// - [ECMAScript reference][spec]
444 /// - [MDN documentation][mdn]
445 ///
446 /// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
447 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators#Less_than_or_equal_operator
448 LessThanOrEqual,
449
450 /// The `in` operator returns `true` if the specified property is in the specified object or
451 /// its prototype chain.
452 ///
453 /// Syntax: `prop in object`
454 ///
455 /// Returns `true` the specified property is in the specified object or its prototype chain.
456 ///
457 /// More information:
458 /// - [ECMAScript reference][spec]
459 /// - [MDN documentation][mdn]
460 ///
461 /// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
462 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in
463 In,
464
465 /// The `instanceof` operator returns `true` if the specified object is an instance of the
466 /// right hand side object.
467 ///
468 /// Syntax: `obj instanceof Object`
469 ///
470 /// Returns `true` the `prototype` property of the right hand side constructor appears anywhere
471 /// in the prototype chain of the object.
472 ///
473 /// More information:
474 /// - [ECMAScript reference][spec]
475 /// - [MDN documentation][mdn]
476 ///
477 /// [spec]: https://tc39.es/ecma262/#prod-RelationalExpression
478 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof
479 InstanceOf,
480}
481
482impl RelationalOp {
483 /// Retrieves the operation as a static string.
484 const fn as_str(self) -> &'static str {
485 match self {
486 Self::Equal => "==",
487 Self::NotEqual => "!=",
488 Self::StrictEqual => "===",
489 Self::StrictNotEqual => "!==",
490 Self::GreaterThan => ">",
491 Self::GreaterThanOrEqual => ">=",
492 Self::LessThan => "<",
493 Self::LessThanOrEqual => "<=",
494 Self::In => "in",
495 Self::InstanceOf => "instanceof",
496 }
497 }
498}
499
500impl Display for RelationalOp {
501 #[inline]
502 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
503 write!(f, "{}", self.as_str())
504 }
505}
506
507/// Logical operators are typically used with Boolean (logical) values; when they are, they return a Boolean value.
508///
509/// However, the `&&` and `||` operators actually return the value of one of the specified operands,
510/// so if these operators are used with non-Boolean values, they may return a non-Boolean value.
511///
512/// More information:
513/// - [ECMAScript reference][spec]
514/// - [MDN documentation][mdn]
515///
516/// [spec]: https://tc39.es/ecma262/#sec-binary-logical-operators
517/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Logical
518#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
519#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
520#[derive(Clone, Copy, Debug, PartialEq, Eq)]
521pub enum LogicalOp {
522 /// The logical AND operator returns the value of the first operand if it can be coerced into `false`;
523 /// otherwise, it returns the second operand.
524 ///
525 /// Syntax: `x && y`
526 ///
527 /// More information:
528 /// - [ECMAScript reference][spec]
529 /// - [MDN documentation][mdn]
530 ///
531 /// [spec]: https://tc39.es/ecma262/#prod-LogicalANDExpression
532 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_AND
533 And,
534
535 /// The logical OR operator returns the value the first operand if it can be coerced into `true`;
536 /// otherwise, it returns the second operand.
537 ///
538 /// Syntax: `x || y`
539 ///
540 /// More information:
541 /// - [ECMAScript reference][spec]
542 /// - [MDN documentation][mdn]
543 ///
544 /// [spec]: https://tc39.es/ecma262/#prod-LogicalORExpression
545 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_OR
546 Or,
547
548 /// The nullish coalescing operator is a logical operator that returns the second operand
549 /// when its first operand is null or undefined, and otherwise returns its first operand.
550 ///
551 /// Syntax: `x ?? y`
552 ///
553 /// More information:
554 /// - [ECMAScript reference][spec]
555 /// - [MDN documentation][mdn]
556 ///
557 /// [spec]: https://tc39.es/ecma262/#prod-CoalesceExpression
558 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
559 Coalesce,
560}
561
562impl LogicalOp {
563 /// Retrieves the operation as a static string.
564 const fn as_str(self) -> &'static str {
565 match self {
566 Self::And => "&&",
567 Self::Or => "||",
568 Self::Coalesce => "??",
569 }
570 }
571}
572
573impl Display for LogicalOp {
574 #[inline]
575 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
576 write!(f, "{}", self.as_str())
577 }
578}