Skip to main content

boa_ast/expression/operator/binary/
mod.rs

1//! Binary expression nodes.
2//!
3//! A Binary expression comprises any operation between two expressions (excluding assignments),
4//! such as:
5//! - [Logic operations][logic] (`||`, `&&`).
6//! - [Relational math][relat] (`==`, `<`).
7//! - [Bit manipulation][bit] (`^`, `|`).
8//! - [Arithmetic][arith] (`+`, `%`).
9//! - The [comma operator][comma] (`,`)
10//!
11//! [logic]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#binary_logical_operators
12//! [relat]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#relational_operators
13//! [bit]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#binary_bitwise_operators
14//! [arith]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#arithmetic_operators
15//! [comma]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
16
17mod op;
18
19use crate::{
20    Span, Spanned,
21    expression::Expression,
22    function::PrivateName,
23    visitor::{VisitWith, Visitor, VisitorMut},
24};
25use boa_interner::{Interner, ToInternedString};
26use core::ops::ControlFlow;
27
28pub use op::*;
29
30/// Binary operations require two operands, one before the operator and one after the operator.
31///
32/// See the [module level documentation][self] for more information.
33#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
34#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
35#[derive(Clone, Debug, PartialEq)]
36pub struct Binary {
37    op: BinaryOp,
38    lhs: Box<Expression>,
39    rhs: Box<Expression>,
40}
41
42impl Binary {
43    /// Creates a `BinOp` AST Expression.
44    #[inline]
45    #[must_use]
46    pub fn new(op: BinaryOp, lhs: Expression, rhs: Expression) -> Self {
47        Self {
48            op,
49            lhs: Box::new(lhs),
50            rhs: Box::new(rhs),
51        }
52    }
53
54    /// Gets the binary operation of the Expression.
55    #[inline]
56    #[must_use]
57    pub const fn op(&self) -> BinaryOp {
58        self.op
59    }
60
61    /// Gets the left hand side of the binary operation.
62    #[inline]
63    #[must_use]
64    pub const fn lhs(&self) -> &Expression {
65        &self.lhs
66    }
67
68    /// Gets the right hand side of the binary operation.
69    #[inline]
70    #[must_use]
71    pub const fn rhs(&self) -> &Expression {
72        &self.rhs
73    }
74
75    /// Gets the left hand side of the binary operation.
76    #[inline]
77    #[must_use]
78    pub fn lhs_mut(&mut self) -> &mut Expression {
79        &mut self.lhs
80    }
81
82    /// Gets the right hand side of the binary operation.
83    #[inline]
84    #[must_use]
85    pub fn rhs_mut(&mut self) -> &mut Expression {
86        &mut self.rhs
87    }
88}
89
90impl Spanned for Binary {
91    #[inline]
92    fn span(&self) -> Span {
93        Span::new(self.lhs.span().start(), self.rhs.span().end())
94    }
95}
96
97impl ToInternedString for Binary {
98    #[inline]
99    fn to_interned_string(&self, interner: &Interner) -> String {
100        format!(
101            "{} {} {}",
102            self.lhs.to_interned_string(interner),
103            self.op,
104            self.rhs.to_interned_string(interner)
105        )
106    }
107}
108
109impl From<Binary> for Expression {
110    #[inline]
111    fn from(op: Binary) -> Self {
112        Self::Binary(op)
113    }
114}
115
116impl VisitWith for Binary {
117    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
118    where
119        V: Visitor<'a>,
120    {
121        visitor.visit_expression(&self.lhs)?;
122        visitor.visit_expression(&self.rhs)
123    }
124
125    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
126    where
127        V: VisitorMut<'a>,
128    {
129        visitor.visit_expression_mut(&mut self.lhs)?;
130        visitor.visit_expression_mut(&mut self.rhs)
131    }
132}
133
134/// Binary [relational][relat] `In` expression with a private name on the left hand side.
135///
136/// Because the left hand side must be a private name, this is a separate type from [`Binary`].
137///
138/// [relat]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#relational_operators
139#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
140#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
141#[derive(Clone, Debug, PartialEq)]
142pub struct BinaryInPrivate {
143    lhs: PrivateName,
144    rhs: Box<Expression>,
145}
146
147impl BinaryInPrivate {
148    /// Creates a `BinaryInPrivate` AST Expression.
149    #[inline]
150    #[must_use]
151    pub fn new(lhs: PrivateName, rhs: Expression) -> Self {
152        Self {
153            lhs,
154            rhs: Box::new(rhs),
155        }
156    }
157
158    /// Gets the left hand side of the binary operation.
159    #[inline]
160    #[must_use]
161    pub const fn lhs(&self) -> &PrivateName {
162        &self.lhs
163    }
164
165    /// Gets the right hand side of the binary operation.
166    #[inline]
167    #[must_use]
168    pub const fn rhs(&self) -> &Expression {
169        &self.rhs
170    }
171}
172
173impl Spanned for BinaryInPrivate {
174    #[inline]
175    fn span(&self) -> Span {
176        Span::new(self.lhs.span().start(), self.rhs.span().end())
177    }
178}
179
180impl ToInternedString for BinaryInPrivate {
181    #[inline]
182    fn to_interned_string(&self, interner: &Interner) -> String {
183        format!(
184            "#{} in {}",
185            interner.resolve_expect(self.lhs.description()),
186            self.rhs.to_interned_string(interner)
187        )
188    }
189}
190
191impl From<BinaryInPrivate> for Expression {
192    #[inline]
193    fn from(op: BinaryInPrivate) -> Self {
194        Self::BinaryInPrivate(op)
195    }
196}
197
198impl VisitWith for BinaryInPrivate {
199    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
200    where
201        V: Visitor<'a>,
202    {
203        visitor.visit_private_name(&self.lhs)?;
204        visitor.visit_expression(&self.rhs)
205    }
206
207    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
208    where
209        V: VisitorMut<'a>,
210    {
211        visitor.visit_private_name_mut(&mut self.lhs)?;
212        visitor.visit_expression_mut(&mut self.rhs)
213    }
214}