1use kind_span::{Range, SyntaxCtxIndex};
4use std::fmt::Display;
5use std::hash::Hash;
6
7#[derive(Clone, Debug)]
12pub struct Symbol {
13 data: String,
14 hash: u64,
15}
16
17impl Symbol {
18 pub fn new(str: String) -> Symbol {
19 Symbol {
20 hash: fxhash::hash64(&str),
21 data: str,
22 }
23 }
24
25 pub fn is_empty(&self) -> bool {
26 self.data.is_empty()
27 }
28}
29
30impl PartialEq for Symbol {
31 fn eq(&self, other: &Self) -> bool {
32 self.hash == other.hash
33 }
34}
35
36impl Hash for Symbol {
37 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
38 state.write_u64(self.hash);
39 }
40}
41
42impl Eq for Symbol {}
43
44#[derive(Clone, Debug, Hash, PartialEq, Eq)]
46pub struct Ident {
47 pub data: Symbol,
48 pub range: Range,
49 pub generated: bool,
50}
51
52#[derive(Clone, Debug, Hash, PartialEq, Eq)]
55pub struct QualifiedIdent {
56 root: Symbol,
57 aux: Option<Symbol>,
58
59 pub range: Range,
60
61 pub generated: bool,
65}
66
67impl QualifiedIdent {
68 pub fn new(root: Symbol, aux: Option<Symbol>, range: Range) -> QualifiedIdent {
69 QualifiedIdent {
70 root,
71 aux,
72 range,
73 generated: false,
74 }
75 }
76
77 #[inline]
81 pub fn to_str(&self) -> &str {
82 &self.root.data
83 }
84
85 #[inline]
86 pub fn get_root(&self) -> String {
87 self.root.data.clone()
88 }
89
90 #[inline]
91 pub fn get_aux(&self) -> Option<Symbol> {
92 self.aux.clone()
93 }
94
95 #[inline]
96 pub fn reset_aux(&mut self) {
97 self.aux = None
98 }
99
100 pub fn change_root(&mut self, str: String) {
101 self.root = Symbol::new(str);
102 }
103
104 pub fn to_generated(&self) -> Self {
105 let mut new = self.clone();
106 new.generated = true;
107 new
108 }
109
110 pub fn to_ident(&self) -> Ident {
112 Ident {
113 data: Symbol::new(self.to_string()),
114 range: self.range,
115 generated: self.generated,
116 }
117 }
118
119 pub fn new_static(root: &str, aux: Option<String>, range: Range) -> QualifiedIdent {
120 QualifiedIdent {
121 root: Symbol::new(root.to_string()),
122 aux: aux.map(Symbol::new),
123 range,
124 generated: false,
125 }
126 }
127
128 pub fn new_sugared(root: &str, extension: &str, range: Range) -> QualifiedIdent {
129 QualifiedIdent {
130 root: Symbol::new(format!("{}.{}", root, extension)),
131 aux: None,
132 range,
133 generated: true,
134 }
135 }
136
137 pub fn pop_last_segment(&self) -> QualifiedIdent {
138 let mut segments = self.root.data.split('.').collect::<Vec<_>>();
139 segments.pop();
140 QualifiedIdent {
141 root: Symbol::new(segments.join(".")),
142 aux: self.aux.clone(),
143 range: self.range,
144 generated: self.generated,
145 }
146 }
147
148 pub fn add_segment(&self, extension: &str) -> QualifiedIdent {
149 QualifiedIdent {
150 root: Symbol::new(format!("{}.{}", self.root.data, extension)),
151 aux: self.aux.clone(),
152 range: self.range,
153 generated: self.generated,
154 }
155 }
156}
157
158impl Ident {
159 pub fn new(data: String, range: Range) -> Ident {
160 Ident {
161 data: Symbol::new(data),
162 range,
163 generated: false,
164 }
165 }
166
167 pub fn new_static(data: &str, range: Range) -> Ident {
168 Ident {
169 data: Symbol::new(data.to_string()),
170 range,
171 generated: false,
172 }
173 }
174
175 pub fn new_by_sugar(data: &str, range: Range) -> Ident {
176 Ident {
177 data: Symbol::new(data.to_string()),
178 range,
179 generated: true,
180 }
181 }
182
183 pub fn with_name(&self, f: fn(String) -> String) -> Ident {
184 let mut new = self.clone();
185 new.data = Symbol::new(f(new.data.data));
186 new
187 }
188
189 pub fn add_underscore(&self) -> Ident {
190 let mut new = self.clone();
191 new.data = Symbol::new(format!("{}_", new.data.data));
192 new
193 }
194
195 #[inline]
196 pub fn to_str(&self) -> &str {
197 &self.data.data
198 }
199
200 pub fn to_generated(&self) -> Self {
201 let mut old = self.clone();
202 old.generated = true;
203 old
204 }
205
206 pub fn to_qualified_ident(&self) -> QualifiedIdent {
207 QualifiedIdent {
208 root: self.data.clone(),
209 aux: None,
210 range: self.range,
211 generated: false,
212 }
213 }
214
215 pub fn decode(num: u64) -> String {
216 let mut num = num;
217 let mut name = String::new();
218 while num > 0 {
219 let chr = (num % 64) as u8;
220 let chr = match chr {
221 0 => '.',
222 1..=10 => (chr - 1 + b'0') as char,
223 11..=36 => (chr - 11 + b'A') as char,
224 37..=62 => (chr - 37 + b'a') as char,
225 63 => '_',
226 64.. => panic!("impossible character value"),
227 };
228 name.push(chr);
229 num /= 64;
230 }
231 name.chars().rev().collect()
232 }
233
234 pub fn encode(&self) -> u64 {
235 fn char_to_u64(chr: char) -> u64 {
236 match chr {
237 '.' => 0,
238 '0'..='9' => 1 + chr as u64 - '0' as u64,
239 'A'..='Z' => 11 + chr as u64 - 'A' as u64,
240 'a'..='z' => 37 + chr as u64 - 'a' as u64,
241 '_' => 63,
242 _ => panic!("Invalid name character."),
243 }
244 }
245
246 let mut num: u64 = 0;
247
248 for (i, chr) in self.to_str().chars().enumerate() {
249 if i < 10 {
250 num = (num << 6) + char_to_u64(chr);
251 }
252 }
253
254 num
255 }
256
257 pub fn set_ctx(&self, ctx: SyntaxCtxIndex) -> Ident {
259 let range = self.range;
260 range.set_ctx(ctx);
261 Ident {
262 data: self.data.clone(),
263 range,
264 generated: false,
265 }
266 }
267
268 pub fn add_segment(&self, name: &str) -> Ident {
269 Ident {
270 data: Symbol::new(format!("{}.{}", self.data.data, name)),
271 range: self.range,
272 generated: false,
273 }
274 }
275
276 pub fn generate(data: &str) -> Ident {
277 Ident {
278 data: Symbol::new(data.to_owned()),
279 range: Range::ghost_range(),
280 generated: true,
281 }
282 }
283}
284
285impl Display for Symbol {
286 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287 write!(f, "{}", self.data)
288 }
289}
290
291impl Display for Ident {
292 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
293 write!(f, "{}", self.data)
294 }
295}
296
297impl Display for QualifiedIdent {
298 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
299 if let Some(aux) = &self.aux {
300 write!(f, "{}/{}", self.root, aux)
301 } else {
302 write!(f, "{}", self.root)
303 }
304 }
305}