mago_syntax/ast/ast/
modifier.rs

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