Skip to main content

mago_syntax/cst/cst/
unary.rs

1use strum::Display;
2
3use mago_span::HasSpan;
4use mago_span::Span;
5
6use crate::cst::cst::expression::Expression;
7use crate::token::GetPrecedence;
8use crate::token::Precedence;
9
10#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Display)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize))]
12#[cfg_attr(feature = "serde", serde(tag = "type", content = "value"))]
13pub enum UnaryPrefixOperator<'arena> {
14    ErrorControl(Span),              // `@$expr`
15    Reference(Span),                 // `&$expr`
16    ArrayCast(Span, &'arena [u8]),   // `(array) $expr`
17    BoolCast(Span, &'arena [u8]),    // `(bool) $expr`
18    BooleanCast(Span, &'arena [u8]), // `(boolean) $expr`
19    DoubleCast(Span, &'arena [u8]),  // `(double) $expr`
20    RealCast(Span, &'arena [u8]),    // `(real) $expr`
21    FloatCast(Span, &'arena [u8]),   // `(float) $expr`
22    IntCast(Span, &'arena [u8]),     // `(int) $expr`
23    IntegerCast(Span, &'arena [u8]), // `(integer) $expr`
24    ObjectCast(Span, &'arena [u8]),  // `(object) $expr`
25    UnsetCast(Span, &'arena [u8]),   // `(unset) $expr`
26    StringCast(Span, &'arena [u8]),  // `(string) $expr`
27    BinaryCast(Span, &'arena [u8]),  // `(binary) $expr`
28    VoidCast(Span, &'arena [u8]),    // `(void) $expr`
29    BitwiseNot(Span),                // `~$expr`
30    Not(Span),                       // `!$expr`
31    PreIncrement(Span),              // `++$expr`
32    PreDecrement(Span),              // `--$expr`
33    Plus(Span),                      // `+$expr`
34    Negation(Span),                  // `-$expr`
35}
36
37#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Display)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize))]
39#[cfg_attr(feature = "serde", serde(tag = "type", content = "value"))]
40pub enum UnaryPostfixOperator {
41    PostIncrement(Span), // `$expr++`
42    PostDecrement(Span), // `$expr--`
43}
44
45#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize))]
47pub struct UnaryPrefix<'arena> {
48    pub operator: UnaryPrefixOperator<'arena>,
49    pub operand: &'arena Expression<'arena>,
50}
51
52#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
53#[cfg_attr(feature = "serde", derive(serde::Serialize))]
54pub struct UnaryPostfix<'arena> {
55    pub operand: &'arena Expression<'arena>,
56    pub operator: UnaryPostfixOperator,
57}
58
59impl<'arena> UnaryPrefixOperator<'arena> {
60    #[inline]
61    #[must_use]
62    pub const fn is_error_control(&self) -> bool {
63        matches!(self, Self::ErrorControl(_))
64    }
65
66    #[inline]
67    #[must_use]
68    pub const fn is_constant(&self) -> bool {
69        matches!(
70            self,
71            Self::BitwiseNot(_)
72                | Self::Not(_)
73                | Self::PreIncrement(_)
74                | Self::PreDecrement(_)
75                | Self::Plus(_)
76                | Self::Negation(_)
77        )
78    }
79
80    #[inline]
81    #[must_use]
82    pub const fn is_cast(&self) -> bool {
83        matches!(
84            self,
85            Self::ArrayCast(_, _)
86                | Self::BoolCast(_, _)
87                | Self::BooleanCast(_, _)
88                | Self::DoubleCast(_, _)
89                | Self::RealCast(_, _)
90                | Self::FloatCast(_, _)
91                | Self::IntCast(_, _)
92                | Self::IntegerCast(_, _)
93                | Self::ObjectCast(_, _)
94                | Self::UnsetCast(_, _)
95                | Self::StringCast(_, _)
96                | Self::BinaryCast(_, _)
97                | Self::VoidCast(_, _)
98        )
99    }
100
101    #[inline]
102    #[must_use]
103    pub const fn is_reference(&self) -> bool {
104        matches!(self, Self::Reference(_))
105    }
106
107    #[inline]
108    #[must_use]
109    pub const fn is_arithmetic(&self) -> bool {
110        matches!(self, Self::Plus(_) | Self::Negation(_) | Self::PreIncrement(_) | Self::PreDecrement(_))
111    }
112
113    #[inline]
114    #[must_use]
115    pub const fn is_increment_or_decrement(&self) -> bool {
116        matches!(self, Self::PreIncrement(_) | Self::PreDecrement(_))
117    }
118
119    #[inline]
120    #[must_use]
121    pub const fn is_not(&self) -> bool {
122        matches!(self, Self::Not(_))
123    }
124
125    #[inline]
126    #[must_use]
127    pub fn as_bytes(&self) -> &'arena [u8] {
128        match self {
129            UnaryPrefixOperator::ErrorControl(_) => b"@",
130            UnaryPrefixOperator::Reference(_) => b"&",
131            UnaryPrefixOperator::ArrayCast(_, value)
132            | UnaryPrefixOperator::BoolCast(_, value)
133            | UnaryPrefixOperator::BooleanCast(_, value)
134            | UnaryPrefixOperator::DoubleCast(_, value)
135            | UnaryPrefixOperator::RealCast(_, value)
136            | UnaryPrefixOperator::FloatCast(_, value)
137            | UnaryPrefixOperator::IntCast(_, value)
138            | UnaryPrefixOperator::IntegerCast(_, value)
139            | UnaryPrefixOperator::ObjectCast(_, value)
140            | UnaryPrefixOperator::UnsetCast(_, value)
141            | UnaryPrefixOperator::StringCast(_, value)
142            | UnaryPrefixOperator::BinaryCast(_, value)
143            | UnaryPrefixOperator::VoidCast(_, value) => value,
144            UnaryPrefixOperator::BitwiseNot(_) => b"~",
145            UnaryPrefixOperator::Not(_) => b"!",
146            UnaryPrefixOperator::PreIncrement(_) => b"++",
147            UnaryPrefixOperator::PreDecrement(_) => b"--",
148            UnaryPrefixOperator::Plus(_) => b"+",
149            UnaryPrefixOperator::Negation(_) => b"-",
150        }
151    }
152
153    #[inline]
154    #[must_use]
155    pub const fn is_same_as(&self, other: &Self) -> bool {
156        matches!(
157            (self, other),
158            (Self::ErrorControl(_), Self::ErrorControl(_))
159                | (Self::Reference(_), Self::Reference(_))
160                | (Self::ArrayCast(_, _), Self::ArrayCast(_, _))
161                | (Self::BoolCast(_, _), Self::BoolCast(_, _))
162                | (Self::BooleanCast(_, _), Self::BooleanCast(_, _))
163                | (Self::DoubleCast(_, _), Self::DoubleCast(_, _))
164                | (Self::RealCast(_, _), Self::RealCast(_, _))
165                | (Self::FloatCast(_, _), Self::FloatCast(_, _))
166                | (Self::IntCast(_, _), Self::IntCast(_, _))
167                | (Self::IntegerCast(_, _), Self::IntegerCast(_, _))
168                | (Self::ObjectCast(_, _), Self::ObjectCast(_, _))
169                | (Self::UnsetCast(_, _), Self::UnsetCast(_, _))
170                | (Self::StringCast(_, _), Self::StringCast(_, _))
171                | (Self::BinaryCast(_, _), Self::BinaryCast(_, _))
172                | (Self::VoidCast(_, _), Self::VoidCast(_, _))
173                | (Self::BitwiseNot(_), Self::BitwiseNot(_))
174                | (Self::Not(_), Self::Not(_))
175                | (Self::PreIncrement(_), Self::PreIncrement(_))
176                | (Self::PreDecrement(_), Self::PreDecrement(_))
177                | (Self::Plus(_), Self::Plus(_))
178                | (Self::Negation(_), Self::Negation(_))
179        )
180    }
181}
182
183impl GetPrecedence for UnaryPrefixOperator<'_> {
184    fn precedence(&self) -> Precedence {
185        match self {
186            Self::Reference(_) => Precedence::Reference,
187            Self::PreIncrement(_) | Self::PreDecrement(_) => Precedence::IncDec,
188            // `!` is the only prefix operator that binds *looser* than `instanceof`
189            // (PHP precedence level just below it), so it keeps `Unary`.
190            Self::Not(_) => Precedence::Unary,
191            // Casts, `~`, unary `+`/`-`, and `@` share one PHP precedence level
192            // that sits *above* `instanceof` and below `**`; `ErrorControl` is
193            // that level. (`(object)1 instanceof X` is `((object)1) instanceof X`.)
194            _ => Precedence::ErrorControl,
195        }
196    }
197}
198
199impl UnaryPostfixOperator {
200    #[inline]
201    #[must_use]
202    pub const fn is_constant(&self) -> bool {
203        match self {
204            Self::PostIncrement(_) | Self::PostDecrement(_) => false,
205        }
206    }
207
208    #[inline]
209    #[must_use]
210    pub const fn as_str<'op>(&self) -> &'op str {
211        match self {
212            UnaryPostfixOperator::PostIncrement(_) => "++",
213            UnaryPostfixOperator::PostDecrement(_) => "--",
214        }
215    }
216
217    #[inline]
218    #[must_use]
219    pub const fn is_same_as(&self, other: &Self) -> bool {
220        matches!(
221            (self, other),
222            (Self::PostIncrement(_), Self::PostIncrement(_)) | (Self::PostDecrement(_), Self::PostDecrement(_))
223        )
224    }
225}
226
227impl GetPrecedence for UnaryPostfixOperator {
228    fn precedence(&self) -> Precedence {
229        match self {
230            Self::PostIncrement(_) | Self::PostDecrement(_) => Precedence::Unary,
231        }
232    }
233}
234
235impl HasSpan for UnaryPrefixOperator<'_> {
236    fn span(&self) -> Span {
237        match self {
238            Self::ErrorControl(span) => *span,
239            Self::Reference(span) => *span,
240            Self::ArrayCast(span, ..) => *span,
241            Self::BoolCast(span, ..) => *span,
242            Self::BooleanCast(span, ..) => *span,
243            Self::DoubleCast(span, ..) => *span,
244            Self::RealCast(span, ..) => *span,
245            Self::FloatCast(span, ..) => *span,
246            Self::IntCast(span, ..) => *span,
247            Self::IntegerCast(span, ..) => *span,
248            Self::ObjectCast(span, ..) => *span,
249            Self::UnsetCast(span, ..) => *span,
250            Self::StringCast(span, ..) => *span,
251            Self::BinaryCast(span, ..) => *span,
252            Self::VoidCast(span, ..) => *span,
253            Self::BitwiseNot(span) => *span,
254            Self::Not(span) => *span,
255            Self::PreIncrement(span) => *span,
256            Self::PreDecrement(span) => *span,
257            Self::Plus(span) => *span,
258            Self::Negation(span) => *span,
259        }
260    }
261}
262
263impl HasSpan for UnaryPostfixOperator {
264    fn span(&self) -> Span {
265        match self {
266            Self::PostIncrement(span) => *span,
267            Self::PostDecrement(span) => *span,
268        }
269    }
270}
271
272impl HasSpan for UnaryPrefix<'_> {
273    fn span(&self) -> Span {
274        self.operator.span().join(self.operand.span())
275    }
276}
277
278impl HasSpan for UnaryPostfix<'_> {
279    fn span(&self) -> Span {
280        self.operand.span().join(self.operator.span())
281    }
282}