kind_tree/
symbol.rs

1//! Describes identifiers and symbols inside the language.
2
3use kind_span::{Range, SyntaxCtxIndex};
4use std::fmt::Display;
5use std::hash::Hash;
6
7/// Stores the name of a variable or constructor.
8/// It's simply a string because in the future i plan
9/// to store all the names and only reference them with
10/// a u64.
11#[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/// Identifier inside a syntax context.
45#[derive(Clone, Debug, Hash, PartialEq, Eq)]
46pub struct Ident {
47    pub data: Symbol,
48    pub range: Range,
49    pub generated: bool,
50}
51
52/// Qualified Identifiers always refer to top level
53/// constructions.
54#[derive(Clone, Debug, Hash, PartialEq, Eq)]
55pub struct QualifiedIdent {
56    root: Symbol,
57    aux: Option<Symbol>,
58
59    pub range: Range,
60
61    /// Flag that is useful to avoid unbound errors while
62    /// trying to collect names created by each of the sintatic
63    /// sugars.
64    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    /// Most of the times a qualified ident will not have the `aux` field
78    /// because it's removed at the `expand_uses` phase. It returns the root
79    /// and avoid a copy of the string.
80    #[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    /// Avoid this function. It transforms a QualifiedIdent into a Ident
111    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    /// Changes the syntax context of the range and of the ident
258    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}