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
98impl ClassLikeMemberName {
99    #[inline]
100    pub fn get_key(&self, interner: &ThreadedInterner) -> String {
101        let class_name = self.class_like.get_key(interner);
102        let member_name = interner.lookup(&self.member.value);
103
104        format!("{}::{}", class_name, member_name)
105    }
106}
107
108impl FunctionLikeName {
109    #[inline]
110    pub const fn is_function(&self) -> bool {
111        matches!(self, FunctionLikeName::Function(_))
112    }
113
114    #[inline]
115    pub const fn is_method_named(&self, value: &StringIdentifier) -> bool {
116        matches!(self, FunctionLikeName::Method(_, name) if name.value.is_same_as(value))
117    }
118
119    #[inline]
120    pub fn get_key(&self, interner: &ThreadedInterner) -> String {
121        match self {
122            FunctionLikeName::Function(name) => interner.lookup(&name.value).to_string(),
123            FunctionLikeName::Method(class_like_name, name) => {
124                let class_name = class_like_name.get_key(interner);
125
126                format!("{}::{}", class_name, interner.lookup(&name.value))
127            }
128            FunctionLikeName::PropertyHook(class_like_name, property_name, name) => {
129                let class_name = class_like_name.get_key(interner);
130
131                format!("{}::{}::{}", class_name, interner.lookup(&property_name.value), interner.lookup(&name.value))
132            }
133            FunctionLikeName::Closure(span) => {
134                format!("closure@{}:{}-{}", interner.lookup(&span.start.source.0), span.start.offset, span.end.offset)
135            }
136            FunctionLikeName::ArrowFunction(span) => {
137                format!(
138                    "arrow-function@{}:{}-{}",
139                    interner.lookup(&span.start.source.0),
140                    span.start.offset,
141                    span.end.offset
142                )
143            }
144        }
145    }
146}
147
148impl HasSpan for Name {
149    fn span(&self) -> Span {
150        self.span
151    }
152}
153
154impl HasSpan for ClassLikeName {
155    fn span(&self) -> Span {
156        match self {
157            ClassLikeName::Class(name) => name.span,
158            ClassLikeName::Interface(name) => name.span,
159            ClassLikeName::Enum(name) => name.span,
160            ClassLikeName::Trait(name) => name.span,
161            ClassLikeName::AnonymousClass(span) => *span,
162        }
163    }
164}
165
166impl HasSpan for ClassLikeMemberName {
167    fn span(&self) -> Span {
168        self.member.span
169    }
170}
171
172impl HasSpan for FunctionLikeName {
173    fn span(&self) -> Span {
174        match self {
175            FunctionLikeName::Function(name) => name.span,
176            FunctionLikeName::Method(_, name) => name.span,
177            FunctionLikeName::PropertyHook(_, _, name) => name.span,
178            FunctionLikeName::Closure(span) => *span,
179            FunctionLikeName::ArrowFunction(span) => *span,
180        }
181    }
182}
183
184impl std::cmp::PartialEq<StringIdentifier> for Name {
185    fn eq(&self, other: &StringIdentifier) -> bool {
186        self.value == *other
187    }
188}
189
190impl std::cmp::PartialEq<Name> for StringIdentifier {
191    fn eq(&self, other: &Name) -> bool {
192        *self == other.value
193    }
194}
195
196impl std::cmp::PartialEq<StringIdentifier> for ClassLikeName {
197    fn eq(&self, other: &StringIdentifier) -> bool {
198        match self {
199            ClassLikeName::Class(id) => id == other,
200            ClassLikeName::Interface(id) => id == other,
201            ClassLikeName::Enum(id) => id == other,
202            ClassLikeName::Trait(id) => id == other,
203            ClassLikeName::AnonymousClass(_) => false,
204        }
205    }
206}
207
208impl std::cmp::PartialEq<ClassLikeName> for StringIdentifier {
209    fn eq(&self, other: &ClassLikeName) -> bool {
210        other == self
211    }
212}