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}