Skip to main content

mago_syntax/ast/ast/
modifier.rs

1use serde::Serialize;
2use strum::Display;
3
4use mago_span::HasSpan;
5use mago_span::Span;
6
7use crate::ast::ast::keyword::Keyword;
8use crate::ast::sequence::Sequence;
9
10/// Represents a modifier statement.
11///
12/// # Examples
13///
14/// ```php
15/// final class Foo {}
16/// ```
17#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, PartialOrd, Ord, Display)]
18#[serde(tag = "type", content = "value")]
19pub enum Modifier<'arena> {
20    Static(Keyword<'arena>),
21    Final(Keyword<'arena>),
22    Abstract(Keyword<'arena>),
23    Readonly(Keyword<'arena>),
24    Public(Keyword<'arena>),
25    PublicSet(Keyword<'arena>),
26    Protected(Keyword<'arena>),
27    ProtectedSet(Keyword<'arena>),
28    Private(Keyword<'arena>),
29    PrivateSet(Keyword<'arena>),
30}
31
32impl<'arena> Modifier<'arena> {
33    #[must_use]
34    pub fn get_keyword(&self) -> &Keyword<'arena> {
35        match self {
36            Modifier::Static(k) => k,
37            Modifier::Final(k) => k,
38            Modifier::Abstract(k) => k,
39            Modifier::Readonly(k) => k,
40            Modifier::Public(k) => k,
41            Modifier::PublicSet(k) => k,
42            Modifier::Protected(k) => k,
43            Modifier::ProtectedSet(k) => k,
44            Modifier::Private(k) => k,
45            Modifier::PrivateSet(k) => k,
46        }
47    }
48
49    /// Returns `true` if the modifier is a visibility modifier.
50    #[must_use]
51    pub fn is_visibility(&self) -> bool {
52        matches!(
53            self,
54            Modifier::Public(..)
55                | Modifier::Protected(..)
56                | Modifier::Private(..)
57                | Modifier::PrivateSet(..)
58                | Modifier::ProtectedSet(..)
59                | Modifier::PublicSet(..)
60        )
61    }
62
63    /// Returns `true` if the modifier is a read visibility modifier.
64    #[must_use]
65    pub fn is_read_visibility(&self) -> bool {
66        matches!(self, Modifier::Public(..) | Modifier::Protected(..) | Modifier::Private(..))
67    }
68
69    /// Returns `true` if the modifier is a write visibility modifier.
70    #[must_use]
71    pub fn is_write_visibility(&self) -> bool {
72        matches!(self, Modifier::PrivateSet(..) | Modifier::ProtectedSet(..) | Modifier::PublicSet(..))
73    }
74
75    #[inline]
76    #[must_use]
77    pub const fn is_static(&self) -> bool {
78        matches!(self, Modifier::Static(..))
79    }
80
81    #[inline]
82    #[must_use]
83    pub const fn is_final(&self) -> bool {
84        matches!(self, Modifier::Final(..))
85    }
86
87    #[inline]
88    #[must_use]
89    pub const fn is_abstract(&self) -> bool {
90        matches!(self, Modifier::Abstract(..))
91    }
92
93    #[inline]
94    #[must_use]
95    pub const fn is_readonly(&self) -> bool {
96        matches!(self, Modifier::Readonly(..))
97    }
98
99    #[inline]
100    #[must_use]
101    pub const fn is_public(&self) -> bool {
102        matches!(self, Modifier::Public(..))
103    }
104
105    #[inline]
106    #[must_use]
107    pub const fn is_protected(&self) -> bool {
108        matches!(self, Modifier::Protected(..))
109    }
110
111    #[inline]
112    #[must_use]
113    pub const fn is_private(&self) -> bool {
114        matches!(self, Modifier::Private(..))
115    }
116
117    #[inline]
118    #[must_use]
119    pub const fn is_public_set(&self) -> bool {
120        matches!(self, Modifier::PublicSet(..))
121    }
122
123    #[inline]
124    #[must_use]
125    pub const fn is_protected_set(&self) -> bool {
126        matches!(self, Modifier::ProtectedSet(..))
127    }
128
129    #[inline]
130    #[must_use]
131    pub const fn is_private_set(&self) -> bool {
132        matches!(self, Modifier::PrivateSet(..))
133    }
134}
135
136impl HasSpan for Modifier<'_> {
137    fn span(&self) -> Span {
138        match self {
139            Modifier::Static(value)
140            | Modifier::Final(value)
141            | Modifier::Abstract(value)
142            | Modifier::Readonly(value)
143            | Modifier::Public(value)
144            | Modifier::Protected(value)
145            | Modifier::Private(value)
146            | Modifier::PrivateSet(value)
147            | Modifier::ProtectedSet(value)
148            | Modifier::PublicSet(value) => value.span(),
149        }
150    }
151}
152
153/// Accessors layered over a modifier [`Sequence`] so that callers can
154/// query visibility, staticness, etc. without pattern-matching every
155/// variant. Imported automatically by `use crate::ast::*`.
156pub trait ModifierSequenceExt<'arena> {
157    fn get_static(&self) -> Option<&Modifier<'arena>>;
158    fn contains_static(&self) -> bool;
159    fn get_final(&self) -> Option<&Modifier<'arena>>;
160    fn contains_final(&self) -> bool;
161    fn get_abstract(&self) -> Option<&Modifier<'arena>>;
162    fn contains_abstract(&self) -> bool;
163    fn get_readonly(&self) -> Option<&Modifier<'arena>>;
164    fn contains_readonly(&self) -> bool;
165    fn get_first_visibility(&self) -> Option<&Modifier<'arena>>;
166    fn get_first_read_visibility(&self) -> Option<&Modifier<'arena>>;
167    fn get_first_write_visibility(&self) -> Option<&Modifier<'arena>>;
168    fn contains_visibility(&self) -> bool;
169    fn get_public(&self) -> Option<&Modifier<'arena>>;
170    fn contains_public(&self) -> bool;
171    fn get_protected(&self) -> Option<&Modifier<'arena>>;
172    fn contains_protected(&self) -> bool;
173    fn get_private(&self) -> Option<&Modifier<'arena>>;
174    fn contains_private(&self) -> bool;
175    fn get_private_set(&self) -> Option<&Modifier<'arena>>;
176    fn contains_private_set(&self) -> bool;
177    fn get_protected_set(&self) -> Option<&Modifier<'arena>>;
178    fn contains_protected_set(&self) -> bool;
179    fn get_public_set(&self) -> Option<&Modifier<'arena>>;
180    fn contains_public_set(&self) -> bool;
181}
182
183impl<'arena> ModifierSequenceExt<'arena> for Sequence<'arena, Modifier<'arena>> {
184    #[inline]
185    fn get_static(&self) -> Option<&Modifier<'arena>> {
186        self.iter().find(|modifier| matches!(modifier, Modifier::Static(..)))
187    }
188
189    #[inline]
190    fn contains_static(&self) -> bool {
191        self.iter().any(|modifier| matches!(modifier, Modifier::Static(..)))
192    }
193
194    #[inline]
195    fn get_final(&self) -> Option<&Modifier<'arena>> {
196        self.iter().find(|modifier| matches!(modifier, Modifier::Final(_)))
197    }
198
199    #[inline]
200    fn contains_final(&self) -> bool {
201        self.iter().any(|modifier| matches!(modifier, Modifier::Final(..)))
202    }
203
204    #[inline]
205    fn get_abstract(&self) -> Option<&Modifier<'arena>> {
206        self.iter().find(|modifier| matches!(modifier, Modifier::Abstract(..)))
207    }
208
209    #[inline]
210    fn contains_abstract(&self) -> bool {
211        self.iter().any(|modifier| matches!(modifier, Modifier::Abstract(..)))
212    }
213
214    #[inline]
215    fn get_readonly(&self) -> Option<&Modifier<'arena>> {
216        self.iter().find(|modifier| matches!(modifier, Modifier::Readonly(..)))
217    }
218
219    #[inline]
220    fn contains_readonly(&self) -> bool {
221        self.iter().any(|modifier| matches!(modifier, Modifier::Readonly(..)))
222    }
223
224    #[inline]
225    fn get_first_visibility(&self) -> Option<&Modifier<'arena>> {
226        self.iter().find(|modifier| {
227            matches!(
228                modifier,
229                Modifier::Public(..)
230                    | Modifier::Protected(..)
231                    | Modifier::Private(..)
232                    | Modifier::PrivateSet(..)
233                    | Modifier::ProtectedSet(..)
234                    | Modifier::PublicSet(..)
235            )
236        })
237    }
238
239    #[inline]
240    fn get_first_read_visibility(&self) -> Option<&Modifier<'arena>> {
241        self.iter()
242            .find(|modifier| matches!(modifier, Modifier::Public(..) | Modifier::Protected(..) | Modifier::Private(..)))
243    }
244
245    #[inline]
246    fn get_first_write_visibility(&self) -> Option<&Modifier<'arena>> {
247        self.iter().find(|modifier| {
248            matches!(modifier, Modifier::PrivateSet(..) | Modifier::ProtectedSet(..) | Modifier::PublicSet(..))
249        })
250    }
251
252    #[inline]
253    fn contains_visibility(&self) -> bool {
254        self.iter().any(Modifier::is_visibility)
255    }
256
257    #[inline]
258    fn get_public(&self) -> Option<&Modifier<'arena>> {
259        self.iter().find(|modifier| matches!(modifier, Modifier::Public(..)))
260    }
261
262    #[inline]
263    fn contains_public(&self) -> bool {
264        self.iter().any(|modifier| matches!(modifier, Modifier::Public(..)))
265    }
266
267    #[inline]
268    fn get_protected(&self) -> Option<&Modifier<'arena>> {
269        self.iter().find(|modifier| matches!(modifier, Modifier::Protected(..)))
270    }
271
272    #[inline]
273    fn contains_protected(&self) -> bool {
274        self.iter().any(|modifier| matches!(modifier, Modifier::Protected(..)))
275    }
276
277    #[inline]
278    fn get_private(&self) -> Option<&Modifier<'arena>> {
279        self.iter().find(|modifier| matches!(modifier, Modifier::Private(..)))
280    }
281
282    #[inline]
283    fn contains_private(&self) -> bool {
284        self.iter().any(|modifier| matches!(modifier, Modifier::Private(..)))
285    }
286
287    #[inline]
288    fn get_private_set(&self) -> Option<&Modifier<'arena>> {
289        self.iter().find(|modifier| matches!(modifier, Modifier::PrivateSet(..)))
290    }
291
292    #[inline]
293    fn contains_private_set(&self) -> bool {
294        self.iter().any(|modifier| matches!(modifier, Modifier::PrivateSet(..)))
295    }
296
297    #[inline]
298    fn get_protected_set(&self) -> Option<&Modifier<'arena>> {
299        self.iter().find(|modifier| matches!(modifier, Modifier::ProtectedSet(..)))
300    }
301
302    #[inline]
303    fn contains_protected_set(&self) -> bool {
304        self.iter().any(|modifier| matches!(modifier, Modifier::ProtectedSet(..)))
305    }
306
307    #[inline]
308    fn get_public_set(&self) -> Option<&Modifier<'arena>> {
309        self.iter().find(|modifier| matches!(modifier, Modifier::PublicSet(..)))
310    }
311
312    #[inline]
313    fn contains_public_set(&self) -> bool {
314        self.iter().any(|modifier| matches!(modifier, Modifier::PublicSet(..)))
315    }
316}