1use serde::Serialize;
2use strum::Display;
3
4use mago_span::HasSpan;
5use mago_span::Span;
6
7use crate::ast::ast::expression::Expression;
8use crate::ast::ast::keyword::Keyword;
9use crate::token::GetPrecedence;
10use crate::token::Precedence;
11
12#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
14#[serde(tag = "type", content = "value")]
15pub enum BinaryOperator<'arena> {
16 Addition(Span), Subtraction(Span), Multiplication(Span), Division(Span), Modulo(Span), Exponentiation(Span), BitwiseAnd(Span), BitwiseOr(Span), BitwiseXor(Span), LeftShift(Span), RightShift(Span), NullCoalesce(Span), Equal(Span), NotEqual(Span), Identical(Span), NotIdentical(Span), AngledNotEqual(Span), LessThan(Span), LessThanOrEqual(Span), GreaterThan(Span), GreaterThanOrEqual(Span), Spaceship(Span), StringConcat(Span), Instanceof(Keyword<'arena>), And(Span), Or(Span), LowAnd(Keyword<'arena>), LowOr(Keyword<'arena>), LowXor(Keyword<'arena>), }
46
47#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord)]
51pub struct Binary<'arena> {
52 pub lhs: &'arena Expression<'arena>,
53 pub operator: BinaryOperator<'arena>,
54 pub rhs: &'arena Expression<'arena>,
55}
56
57impl<'arena> BinaryOperator<'arena> {
58 #[inline]
59 #[must_use]
60 pub const fn is_constant(&self) -> bool {
61 !matches!(self, Self::Instanceof(_))
62 }
63
64 #[inline]
65 #[must_use]
66 pub const fn is_multiplicative(&self) -> bool {
67 matches!(self, Self::Multiplication(_) | Self::Division(_) | Self::Modulo(_))
68 }
69
70 #[inline]
71 #[must_use]
72 pub const fn is_additive(&self) -> bool {
73 matches!(self, Self::Addition(_) | Self::Subtraction(_))
74 }
75
76 #[inline]
77 #[must_use]
78 pub const fn is_arithmetic(&self) -> bool {
79 matches!(
80 self,
81 Self::Addition(_)
82 | Self::Subtraction(_)
83 | Self::Multiplication(_)
84 | Self::Division(_)
85 | Self::Modulo(_)
86 | Self::Exponentiation(_)
87 )
88 }
89
90 #[inline]
91 #[must_use]
92 pub const fn is_bit_shift(&self) -> bool {
93 matches!(self, Self::LeftShift(_) | Self::RightShift(_))
94 }
95
96 #[inline]
97 #[must_use]
98 pub const fn is_bitwise(&self) -> bool {
99 matches!(
100 self,
101 Self::BitwiseAnd(_) | Self::BitwiseOr(_) | Self::BitwiseXor(_) | Self::LeftShift(_) | Self::RightShift(_)
102 )
103 }
104
105 #[inline]
106 #[must_use]
107 pub const fn is_equality(&self) -> bool {
108 matches!(
109 self,
110 Self::Equal(_)
111 | Self::NotEqual(_)
112 | Self::Identical(_)
113 | Self::NotIdentical(_)
114 | Self::AngledNotEqual(_)
115 | Self::Spaceship(_)
116 )
117 }
118
119 #[must_use]
120 pub const fn is_negated_equality(&self) -> bool {
121 matches!(self, Self::NotEqual(_) | Self::NotIdentical(_) | Self::AngledNotEqual(_))
122 }
123
124 #[inline]
125 #[must_use]
126 pub const fn is_identity(&self) -> bool {
127 matches!(self, Self::Identical(_) | Self::NotIdentical(_))
128 }
129
130 #[inline]
131 #[must_use]
132 pub const fn is_comparison(&self) -> bool {
133 matches!(
134 self,
135 Self::Equal(_)
136 | Self::NotEqual(_)
137 | Self::Identical(_)
138 | Self::NotIdentical(_)
139 | Self::AngledNotEqual(_)
140 | Self::LessThan(_)
141 | Self::LessThanOrEqual(_)
142 | Self::GreaterThan(_)
143 | Self::GreaterThanOrEqual(_)
144 | Self::Spaceship(_)
145 )
146 }
147
148 #[inline]
149 #[must_use]
150 pub const fn is_logical(&self) -> bool {
151 matches!(self, Self::And(_) | Self::Or(_) | Self::LowAnd(_) | Self::LowOr(_) | Self::LowXor(_))
152 }
153
154 #[inline]
155 #[must_use]
156 pub const fn is_low_precedence(&self) -> bool {
157 matches!(self, Self::LowAnd(_) | Self::LowOr(_) | Self::LowXor(_))
158 }
159
160 #[inline]
161 #[must_use]
162 pub const fn is_concatenation(&self) -> bool {
163 matches!(self, Self::StringConcat(_))
164 }
165
166 #[inline]
167 #[must_use]
168 pub const fn is_null_coalesce(&self) -> bool {
169 matches!(self, Self::NullCoalesce(_))
170 }
171
172 #[inline]
173 #[must_use]
174 pub const fn is_instanceof(&self) -> bool {
175 matches!(self, Self::Instanceof(_))
176 }
177
178 #[inline]
179 #[must_use]
180 pub fn as_str(&self) -> &'arena str {
181 match self {
182 Self::Addition(_) => "+",
183 Self::Subtraction(_) => "-",
184 Self::Multiplication(_) => "*",
185 Self::Division(_) => "/",
186 Self::Modulo(_) => "%",
187 Self::Exponentiation(_) => "**",
188 Self::BitwiseAnd(_) => "&",
189 Self::BitwiseOr(_) => "|",
190 Self::BitwiseXor(_) => "^",
191 Self::LeftShift(_) => "<<",
192 Self::RightShift(_) => ">>",
193 Self::NullCoalesce(_) => "??",
194 Self::Equal(_) => "==",
195 Self::NotEqual(_) => "!=",
196 Self::Identical(_) => "===",
197 Self::NotIdentical(_) => "!==",
198 Self::AngledNotEqual(_) => "<>",
199 Self::LessThan(_) => "<",
200 Self::LessThanOrEqual(_) => "<=",
201 Self::GreaterThan(_) => ">",
202 Self::GreaterThanOrEqual(_) => ">=",
203 Self::Spaceship(_) => "<=>",
204 Self::StringConcat(_) => ".",
205 Self::And(_) => "&&",
206 Self::Or(_) => "||",
207 Self::Instanceof(keyword) => keyword.value,
208 Self::LowAnd(keyword) => keyword.value,
209 Self::LowOr(keyword) => keyword.value,
210 Self::LowXor(keyword) => keyword.value,
211 }
212 }
213
214 #[inline]
215 #[must_use]
216 pub const fn is_same_as(&self, other: &Self) -> bool {
217 matches!(
218 (self, other),
219 (Self::Addition(_), Self::Addition(_))
220 | (Self::Subtraction(_), Self::Subtraction(_))
221 | (Self::Multiplication(_), Self::Multiplication(_))
222 | (Self::Division(_), Self::Division(_))
223 | (Self::Modulo(_), Self::Modulo(_))
224 | (Self::Exponentiation(_), Self::Exponentiation(_))
225 | (Self::BitwiseAnd(_), Self::BitwiseAnd(_))
226 | (Self::BitwiseOr(_), Self::BitwiseOr(_))
227 | (Self::BitwiseXor(_), Self::BitwiseXor(_))
228 | (Self::LeftShift(_), Self::LeftShift(_))
229 | (Self::RightShift(_), Self::RightShift(_))
230 | (Self::NullCoalesce(_), Self::NullCoalesce(_))
231 | (Self::Equal(_), Self::Equal(_))
232 | (Self::NotEqual(_), Self::NotEqual(_))
233 | (Self::Identical(_), Self::Identical(_))
234 | (Self::NotIdentical(_), Self::NotIdentical(_))
235 | (Self::AngledNotEqual(_), Self::AngledNotEqual(_))
236 | (Self::LessThan(_), Self::LessThan(_))
237 | (Self::LessThanOrEqual(_), Self::LessThanOrEqual(_))
238 | (Self::GreaterThan(_), Self::GreaterThan(_))
239 | (Self::GreaterThanOrEqual(_), Self::GreaterThanOrEqual(_))
240 | (Self::Spaceship(_), Self::Spaceship(_))
241 | (Self::StringConcat(_), Self::StringConcat(_))
242 | (Self::Instanceof(_), Self::Instanceof(_))
243 | (Self::And(_), Self::And(_))
244 | (Self::Or(_), Self::Or(_))
245 | (Self::LowAnd(_), Self::LowAnd(_))
246 | (Self::LowOr(_), Self::LowOr(_))
247 | (Self::LowXor(_), Self::LowXor(_))
248 )
249 }
250}
251
252impl GetPrecedence for BinaryOperator<'_> {
253 #[inline]
254 fn precedence(&self) -> Precedence {
255 match self {
256 Self::Addition(_) | Self::Subtraction(_) => Precedence::AddSub,
257 Self::Multiplication(_) | Self::Division(_) | Self::Modulo(_) => Precedence::MulDivMod,
258 Self::Exponentiation(_) => Precedence::Pow,
259 Self::BitwiseAnd(_) => Precedence::BitwiseAnd,
260 Self::BitwiseOr(_) => Precedence::BitwiseOr,
261 Self::BitwiseXor(_) => Precedence::BitwiseXor,
262 Self::LeftShift(_) | Self::RightShift(_) => Precedence::BitShift,
263 Self::NullCoalesce(_) => Precedence::NullCoalesce,
264 Self::Equal(_)
265 | Self::NotEqual(_)
266 | Self::Identical(_)
267 | Self::NotIdentical(_)
268 | Self::AngledNotEqual(_)
269 | Self::Spaceship(_) => Precedence::Equality,
270 Self::LessThan(_) | Self::LessThanOrEqual(_) | Self::GreaterThan(_) | Self::GreaterThanOrEqual(_) => {
271 Precedence::Comparison
272 }
273 Self::StringConcat(_) => Precedence::Concat,
274 Self::And(_) => Precedence::And,
275 Self::Or(_) => Precedence::Or,
276 Self::LowAnd(_) => Precedence::KeyAnd,
277 Self::LowOr(_) => Precedence::KeyOr,
278 Self::LowXor(_) => Precedence::KeyXor,
279 Self::Instanceof(_) => Precedence::Instanceof,
280 }
281 }
282}
283
284impl HasSpan for BinaryOperator<'_> {
285 fn span(&self) -> Span {
286 match self {
287 Self::Addition(span) => *span,
288 Self::Subtraction(span) => *span,
289 Self::Multiplication(span) => *span,
290 Self::Division(span) => *span,
291 Self::Modulo(span) => *span,
292 Self::Exponentiation(span) => *span,
293 Self::BitwiseAnd(span) => *span,
294 Self::BitwiseOr(span) => *span,
295 Self::BitwiseXor(span) => *span,
296 Self::LeftShift(span) => *span,
297 Self::RightShift(span) => *span,
298 Self::NullCoalesce(span) => *span,
299 Self::Equal(span) => *span,
300 Self::NotEqual(span) => *span,
301 Self::Identical(span) => *span,
302 Self::NotIdentical(span) => *span,
303 Self::AngledNotEqual(span) => *span,
304 Self::LessThan(span) => *span,
305 Self::LessThanOrEqual(span) => *span,
306 Self::GreaterThan(span) => *span,
307 Self::GreaterThanOrEqual(span) => *span,
308 Self::Spaceship(span) => *span,
309 Self::StringConcat(span) => *span,
310 Self::Instanceof(keyword) => keyword.span(),
311 Self::And(span) => *span,
312 Self::Or(span) => *span,
313 Self::LowAnd(keyword) => keyword.span(),
314 Self::LowOr(keyword) => keyword.span(),
315 Self::LowXor(keyword) => keyword.span(),
316 }
317 }
318}
319
320impl HasSpan for Binary<'_> {
321 fn span(&self) -> Span {
322 self.lhs.span().join(self.rhs.span())
323 }
324}