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}