mago_reflection/
identifier.rs

1use mago_interner::ThreadedInterner;
2use serde::Deserialize;
3use serde::Serialize;
4
5use mago_interner::StringIdentifier;
6use mago_span::HasSpan;
7use mago_span::Span;
8
9#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
10pub struct Name {
11    pub value: StringIdentifier,
12    pub span: Span,
13}
14
15#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
16pub enum ClassLikeName {
17    Class(Name),
18    Interface(Name),
19    Enum(Name),
20    Trait(Name),
21    AnonymousClass(Span),
22}
23
24#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
25pub struct ClassLikeMemberName {
26    pub class_like: ClassLikeName,
27    pub member: Name,
28}
29
30#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
31pub enum FunctionLikeName {
32    Function(Name),
33    Method(ClassLikeName, Name),
34    PropertyHook(ClassLikeName, Name, Name),
35    Closure(Span),
36    ArrowFunction(Span),
37}
38
39impl Name {
40    #[inline]
41    pub const fn new(value: StringIdentifier, span: Span) -> Self {
42        Name { value, span }
43    }
44}
45
46impl ClassLikeName {
47    #[inline]
48    pub const fn inner(&self) -> Option<&Name> {
49        match self {
50            ClassLikeName::Class(name) => Some(name),
51            ClassLikeName::Interface(name) => Some(name),
52            ClassLikeName::Enum(name) => Some(name),
53            ClassLikeName::Trait(name) => Some(name),
54            ClassLikeName::AnonymousClass(_) => None,
55        }
56    }
57
58    #[inline]
59    pub const fn inner_unchecked(&self) -> &Name {
60        match self {
61            ClassLikeName::Class(name) => name,
62            ClassLikeName::Interface(name) => name,
63            ClassLikeName::Enum(name) => name,
64            ClassLikeName::Trait(name) => name,
65            ClassLikeName::AnonymousClass(_) => unreachable!(),
66        }
67    }
68
69    #[inline]
70    pub fn get_key(&self, interner: &ThreadedInterner) -> String {
71        match self {
72            ClassLikeName::Class(name)
73            | ClassLikeName::Interface(name)
74            | ClassLikeName::Enum(name)
75            | ClassLikeName::Trait(name) => interner.lookup(&name.value).to_string(),
76            ClassLikeName::AnonymousClass(span) => {
77                format!(
78                    "anonymous-class@{}:{}-{}",
79                    interner.lookup(&span.start.source.0),
80                    span.start.offset,
81                    span.end.offset
82                )
83            }
84        }
85    }
86
87    #[inline]
88    pub const fn get_kind(&self) -> &'static str {
89        match self {
90            ClassLikeName::AnonymousClass(_) | ClassLikeName::Class(_) => "Class",
91            ClassLikeName::Interface(_) => "Interface",
92            ClassLikeName::Enum(_) => "Enum",
93            ClassLikeName::Trait(_) => "Trait",
94        }
95    }
96
97    #[inline]
98    pub const fn is_class(&self) -> bool {
99        matches!(self, ClassLikeName::Class(_))
100    }
101
102    #[inline]
103    pub const fn is_interface(&self) -> bool {
104        matches!(self, ClassLikeName::Interface(_))
105    }
106
107    #[inline]
108    pub const fn is_enum(&self) -> bool {
109        matches!(self, ClassLikeName::Enum(_))
110    }
111
112    #[inline]
113    pub const fn is_trait(&self) -> bool {
114        matches!(self, ClassLikeName::Trait(_))
115    }
116
117    #[inline]
118    pub const fn is_anonymous_class(&self) -> bool {
119        matches!(self, ClassLikeName::AnonymousClass(_))
120    }
121}
122
123impl ClassLikeMemberName {
124    #[inline]
125    pub fn get_key(&self, interner: &ThreadedInterner) -> String {
126        let class_name = self.class_like.get_key(interner);
127        let member_name = interner.lookup(&self.member.value);
128
129        format!("{class_name}::{member_name}")
130    }
131}
132
133impl FunctionLikeName {
134    #[inline]
135    pub const fn is_function(&self) -> bool {
136        matches!(self, FunctionLikeName::Function(_))
137    }
138
139    #[inline]
140    pub const fn is_method_named(&self, value: &StringIdentifier) -> bool {
141        matches!(self, FunctionLikeName::Method(_, name) if name.value.is_same_as(value))
142    }
143
144    #[inline]
145    pub fn get_key(&self, interner: &ThreadedInterner) -> String {
146        match self {
147            FunctionLikeName::Function(name) => interner.lookup(&name.value).to_string(),
148            FunctionLikeName::Method(class_like_name, name) => {
149                let class_name = class_like_name.get_key(interner);
150
151                format!("{}::{}", class_name, interner.lookup(&name.value))
152            }
153            FunctionLikeName::PropertyHook(class_like_name, property_name, name) => {
154                let class_name = class_like_name.get_key(interner);
155
156                format!("{}::{}::{}", class_name, interner.lookup(&property_name.value), interner.lookup(&name.value))
157            }
158            FunctionLikeName::Closure(span) => {
159                format!("closure@{}:{}-{}", interner.lookup(&span.start.source.0), span.start.offset, span.end.offset)
160            }
161            FunctionLikeName::ArrowFunction(span) => {
162                format!(
163                    "arrow-function@{}:{}-{}",
164                    interner.lookup(&span.start.source.0),
165                    span.start.offset,
166                    span.end.offset
167                )
168            }
169        }
170    }
171}
172
173impl HasSpan for Name {
174    fn span(&self) -> Span {
175        self.span
176    }
177}
178
179impl HasSpan for ClassLikeName {
180    fn span(&self) -> Span {
181        match self {
182            ClassLikeName::Class(name) => name.span,
183            ClassLikeName::Interface(name) => name.span,
184            ClassLikeName::Enum(name) => name.span,
185            ClassLikeName::Trait(name) => name.span,
186            ClassLikeName::AnonymousClass(span) => *span,
187        }
188    }
189}
190
191impl HasSpan for ClassLikeMemberName {
192    fn span(&self) -> Span {
193        self.member.span
194    }
195}
196
197impl HasSpan for FunctionLikeName {
198    fn span(&self) -> Span {
199        match self {
200            FunctionLikeName::Function(name) => name.span,
201            FunctionLikeName::Method(_, name) => name.span,
202            FunctionLikeName::PropertyHook(_, _, name) => name.span,
203            FunctionLikeName::Closure(span) => *span,
204            FunctionLikeName::ArrowFunction(span) => *span,
205        }
206    }
207}
208
209impl std::cmp::PartialEq<StringIdentifier> for Name {
210    fn eq(&self, other: &StringIdentifier) -> bool {
211        self.value == *other
212    }
213}
214
215impl std::cmp::PartialEq<Name> for StringIdentifier {
216    fn eq(&self, other: &Name) -> bool {
217        *self == other.value
218    }
219}
220
221impl std::cmp::PartialEq<StringIdentifier> for ClassLikeName {
222    fn eq(&self, other: &StringIdentifier) -> bool {
223        match self {
224            ClassLikeName::Class(id) => id == other,
225            ClassLikeName::Interface(id) => id == other,
226            ClassLikeName::Enum(id) => id == other,
227            ClassLikeName::Trait(id) => id == other,
228            ClassLikeName::AnonymousClass(_) => false,
229        }
230    }
231}
232
233impl std::cmp::PartialEq<ClassLikeName> for StringIdentifier {
234    fn eq(&self, other: &ClassLikeName) -> bool {
235        other == self
236    }
237}