mago_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::keyword::Keyword;
10use crate::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    pub fn as_str<'a>(&self, interner: &'a ThreadedInterner) -> &'a str {
75        match self {
76            Modifier::Static(k) => interner.lookup(&k.value),
77            Modifier::Final(k) => interner.lookup(&k.value),
78            Modifier::Abstract(k) => interner.lookup(&k.value),
79            Modifier::Readonly(k) => interner.lookup(&k.value),
80            Modifier::Public(k) => interner.lookup(&k.value),
81            Modifier::Protected(k) => interner.lookup(&k.value),
82            Modifier::Private(k) => interner.lookup(&k.value),
83            Modifier::PrivateSet(k) => interner.lookup(&k.value),
84            Modifier::ProtectedSet(k) => interner.lookup(&k.value),
85            Modifier::PublicSet(k) => interner.lookup(&k.value),
86        }
87    }
88}
89
90impl HasSpan for Modifier {
91    fn span(&self) -> Span {
92        match self {
93            Modifier::Static(value)
94            | Modifier::Final(value)
95            | Modifier::Abstract(value)
96            | Modifier::Readonly(value)
97            | Modifier::Public(value)
98            | Modifier::Protected(value)
99            | Modifier::Private(value)
100            | Modifier::PrivateSet(value)
101            | Modifier::ProtectedSet(value)
102            | Modifier::PublicSet(value) => value.span(),
103        }
104    }
105}
106
107impl Sequence<Modifier> {
108    /// Returns the first abstract modifier in the sequence, if any.
109    pub fn get_static(&self) -> Option<&Modifier> {
110        self.iter().find(|modifier| matches!(modifier, Modifier::Static(..)))
111    }
112
113    /// Returns `true` if the sequence contains a static modifier.
114    pub fn contains_static(&self) -> bool {
115        self.iter().any(|modifier| matches!(modifier, Modifier::Static(..)))
116    }
117
118    /// Return the first final modifier in the sequence, if any.
119    pub fn get_final(&self) -> Option<&Modifier> {
120        self.iter().find(|modifier| matches!(modifier, Modifier::Final(_)))
121    }
122
123    /// Returns `true` if the sequence contains a final modifier.
124    pub fn contains_final(&self) -> bool {
125        self.iter().any(|modifier| matches!(modifier, Modifier::Final(..)))
126    }
127
128    /// Returns the first abstract modifier in the sequence, if any.
129    pub fn get_abstract(&self) -> Option<&Modifier> {
130        self.iter().find(|modifier| matches!(modifier, Modifier::Abstract(..)))
131    }
132
133    /// Returns `true` if the sequence contains an abstract modifier.
134    pub fn contains_abstract(&self) -> bool {
135        self.iter().any(|modifier| matches!(modifier, Modifier::Abstract(..)))
136    }
137
138    /// Returns the first abstract modifier in the sequence, if any.
139    pub fn get_readonly(&self) -> Option<&Modifier> {
140        self.iter().find(|modifier| matches!(modifier, Modifier::Readonly(..)))
141    }
142
143    /// Returns `true` if the sequence contains a readonly modifier.
144    pub fn contains_readonly(&self) -> bool {
145        self.iter().any(|modifier| matches!(modifier, Modifier::Readonly(..)))
146    }
147
148    pub fn get_first_visibility(&self) -> Option<&Modifier> {
149        self.iter().find(|modifier| {
150            matches!(
151                modifier,
152                Modifier::Public(..)
153                    | Modifier::Protected(..)
154                    | Modifier::Private(..)
155                    | Modifier::PrivateSet(..)
156                    | Modifier::ProtectedSet(..)
157                    | Modifier::PublicSet(..)
158            )
159        })
160    }
161
162    pub fn get_first_read_visibility(&self) -> Option<&Modifier> {
163        self.iter()
164            .find(|modifier| matches!(modifier, Modifier::Public(..) | Modifier::Protected(..) | Modifier::Private(..)))
165    }
166
167    pub fn get_first_write_visibility(&self) -> Option<&Modifier> {
168        self.iter().find(|modifier| {
169            matches!(modifier, Modifier::PrivateSet(..) | Modifier::ProtectedSet(..) | Modifier::PublicSet(..))
170        })
171    }
172
173    /// Returns `true` if the sequence contains a visibility modifier for reading or writing.
174    pub fn contains_visibility(&self) -> bool {
175        self.iter().any(Modifier::is_visibility)
176    }
177
178    pub fn get_public(&self) -> Option<&Modifier> {
179        self.iter().find(|modifier| matches!(modifier, Modifier::Public(..)))
180    }
181
182    /// Returns `true` if the sequence contains a public visibility modifier.
183    pub fn contains_public(&self) -> bool {
184        self.iter().any(|modifier| matches!(modifier, Modifier::Public(..)))
185    }
186
187    pub fn get_protected(&self) -> Option<&Modifier> {
188        self.iter().find(|modifier| matches!(modifier, Modifier::Protected(..)))
189    }
190
191    /// Returns `true` if the sequence contains a protected visibility modifier.
192    pub fn contains_protected(&self) -> bool {
193        self.iter().any(|modifier| matches!(modifier, Modifier::Protected(..)))
194    }
195
196    pub fn get_private(&self) -> Option<&Modifier> {
197        self.iter().find(|modifier| matches!(modifier, Modifier::Private(..)))
198    }
199
200    /// Returns `true` if the sequence contains a private visibility modifier.
201    pub fn contains_private(&self) -> bool {
202        self.iter().any(|modifier| matches!(modifier, Modifier::Private(..)))
203    }
204
205    pub fn get_private_set(&self) -> Option<&Modifier> {
206        self.iter().find(|modifier| matches!(modifier, Modifier::PrivateSet(..)))
207    }
208
209    pub fn contains_private_set(&self) -> bool {
210        self.iter().any(|modifier| matches!(modifier, Modifier::PrivateSet(..)))
211    }
212
213    pub fn get_protected_set(&self) -> Option<&Modifier> {
214        self.iter().find(|modifier| matches!(modifier, Modifier::ProtectedSet(..)))
215    }
216
217    pub fn contains_protected_set(&self) -> bool {
218        self.iter().any(|modifier| matches!(modifier, Modifier::ProtectedSet(..)))
219    }
220
221    pub fn get_public_set(&self) -> Option<&Modifier> {
222        self.iter().find(|modifier| matches!(modifier, Modifier::PublicSet(..)))
223    }
224
225    pub fn contains_public_set(&self) -> bool {
226        self.iter().any(|modifier| matches!(modifier, Modifier::PublicSet(..)))
227    }
228}