diff options
Diffstat (limited to 'crates/hir_expand/src/name.rs')
-rw-r--r-- | crates/hir_expand/src/name.rs | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs new file mode 100644 index 000000000..49841c7a1 --- /dev/null +++ b/crates/hir_expand/src/name.rs | |||
@@ -0,0 +1,230 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use std::fmt; | ||
4 | |||
5 | use syntax::{ast, SmolStr}; | ||
6 | |||
7 | /// `Name` is a wrapper around string, which is used in hir for both references | ||
8 | /// and declarations. In theory, names should also carry hygiene info, but we are | ||
9 | /// not there yet! | ||
10 | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
11 | pub struct Name(Repr); | ||
12 | |||
13 | #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] | ||
14 | enum Repr { | ||
15 | Text(SmolStr), | ||
16 | TupleField(usize), | ||
17 | } | ||
18 | |||
19 | impl fmt::Display for Name { | ||
20 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
21 | match &self.0 { | ||
22 | Repr::Text(text) => fmt::Display::fmt(&text, f), | ||
23 | Repr::TupleField(idx) => fmt::Display::fmt(&idx, f), | ||
24 | } | ||
25 | } | ||
26 | } | ||
27 | |||
28 | impl Name { | ||
29 | /// Note: this is private to make creating name from random string hard. | ||
30 | /// Hopefully, this should allow us to integrate hygiene cleaner in the | ||
31 | /// future, and to switch to interned representation of names. | ||
32 | const fn new_text(text: SmolStr) -> Name { | ||
33 | Name(Repr::Text(text)) | ||
34 | } | ||
35 | |||
36 | pub fn new_tuple_field(idx: usize) -> Name { | ||
37 | Name(Repr::TupleField(idx)) | ||
38 | } | ||
39 | |||
40 | pub fn new_lifetime(lt: &syntax::SyntaxToken) -> Name { | ||
41 | assert!(lt.kind() == syntax::SyntaxKind::LIFETIME); | ||
42 | Name(Repr::Text(lt.text().clone())) | ||
43 | } | ||
44 | |||
45 | /// Shortcut to create inline plain text name | ||
46 | const fn new_inline_ascii(text: &[u8]) -> Name { | ||
47 | Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text)) | ||
48 | } | ||
49 | |||
50 | /// Resolve a name from the text of token. | ||
51 | fn resolve(raw_text: &SmolStr) -> Name { | ||
52 | let raw_start = "r#"; | ||
53 | if raw_text.as_str().starts_with(raw_start) { | ||
54 | Name::new_text(SmolStr::new(&raw_text[raw_start.len()..])) | ||
55 | } else { | ||
56 | Name::new_text(raw_text.clone()) | ||
57 | } | ||
58 | } | ||
59 | |||
60 | pub fn missing() -> Name { | ||
61 | Name::new_text("[missing name]".into()) | ||
62 | } | ||
63 | |||
64 | pub fn as_tuple_index(&self) -> Option<usize> { | ||
65 | match self.0 { | ||
66 | Repr::TupleField(idx) => Some(idx), | ||
67 | _ => None, | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | pub trait AsName { | ||
73 | fn as_name(&self) -> Name; | ||
74 | } | ||
75 | |||
76 | impl AsName for ast::NameRef { | ||
77 | fn as_name(&self) -> Name { | ||
78 | match self.as_tuple_field() { | ||
79 | Some(idx) => Name::new_tuple_field(idx), | ||
80 | None => Name::resolve(self.text()), | ||
81 | } | ||
82 | } | ||
83 | } | ||
84 | |||
85 | impl AsName for ast::Name { | ||
86 | fn as_name(&self) -> Name { | ||
87 | Name::resolve(self.text()) | ||
88 | } | ||
89 | } | ||
90 | |||
91 | impl AsName for ast::NameOrNameRef { | ||
92 | fn as_name(&self) -> Name { | ||
93 | match self { | ||
94 | ast::NameOrNameRef::Name(it) => it.as_name(), | ||
95 | ast::NameOrNameRef::NameRef(it) => it.as_name(), | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | impl AsName for tt::Ident { | ||
101 | fn as_name(&self) -> Name { | ||
102 | Name::resolve(&self.text) | ||
103 | } | ||
104 | } | ||
105 | |||
106 | impl AsName for ast::FieldKind { | ||
107 | fn as_name(&self) -> Name { | ||
108 | match self { | ||
109 | ast::FieldKind::Name(nr) => nr.as_name(), | ||
110 | ast::FieldKind::Index(idx) => { | ||
111 | let idx = idx.text().parse::<usize>().unwrap_or(0); | ||
112 | Name::new_tuple_field(idx) | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
118 | impl AsName for base_db::Dependency { | ||
119 | fn as_name(&self) -> Name { | ||
120 | Name::new_text(SmolStr::new(&*self.name)) | ||
121 | } | ||
122 | } | ||
123 | |||
124 | pub mod known { | ||
125 | macro_rules! known_names { | ||
126 | ($($ident:ident),* $(,)?) => { | ||
127 | $( | ||
128 | #[allow(bad_style)] | ||
129 | pub const $ident: super::Name = | ||
130 | super::Name::new_inline_ascii(stringify!($ident).as_bytes()); | ||
131 | )* | ||
132 | }; | ||
133 | } | ||
134 | |||
135 | known_names!( | ||
136 | // Primitives | ||
137 | isize, | ||
138 | i8, | ||
139 | i16, | ||
140 | i32, | ||
141 | i64, | ||
142 | i128, | ||
143 | usize, | ||
144 | u8, | ||
145 | u16, | ||
146 | u32, | ||
147 | u64, | ||
148 | u128, | ||
149 | f32, | ||
150 | f64, | ||
151 | bool, | ||
152 | char, | ||
153 | str, | ||
154 | // Special names | ||
155 | macro_rules, | ||
156 | doc, | ||
157 | // Components of known path (value or mod name) | ||
158 | std, | ||
159 | core, | ||
160 | alloc, | ||
161 | iter, | ||
162 | ops, | ||
163 | future, | ||
164 | result, | ||
165 | boxed, | ||
166 | // Components of known path (type name) | ||
167 | IntoIterator, | ||
168 | Item, | ||
169 | Try, | ||
170 | Ok, | ||
171 | Future, | ||
172 | Result, | ||
173 | Output, | ||
174 | Target, | ||
175 | Box, | ||
176 | RangeFrom, | ||
177 | RangeFull, | ||
178 | RangeInclusive, | ||
179 | RangeToInclusive, | ||
180 | RangeTo, | ||
181 | Range, | ||
182 | Neg, | ||
183 | Not, | ||
184 | Index, | ||
185 | // Builtin macros | ||
186 | file, | ||
187 | column, | ||
188 | compile_error, | ||
189 | line, | ||
190 | assert, | ||
191 | stringify, | ||
192 | concat, | ||
193 | include, | ||
194 | include_bytes, | ||
195 | include_str, | ||
196 | format_args, | ||
197 | format_args_nl, | ||
198 | env, | ||
199 | option_env, | ||
200 | // Builtin derives | ||
201 | Copy, | ||
202 | Clone, | ||
203 | Default, | ||
204 | Debug, | ||
205 | Hash, | ||
206 | Ord, | ||
207 | PartialOrd, | ||
208 | Eq, | ||
209 | PartialEq, | ||
210 | ); | ||
211 | |||
212 | // self/Self cannot be used as an identifier | ||
213 | pub const SELF_PARAM: super::Name = super::Name::new_inline_ascii(b"self"); | ||
214 | pub const SELF_TYPE: super::Name = super::Name::new_inline_ascii(b"Self"); | ||
215 | |||
216 | #[macro_export] | ||
217 | macro_rules! name { | ||
218 | (self) => { | ||
219 | $crate::name::known::SELF_PARAM | ||
220 | }; | ||
221 | (Self) => { | ||
222 | $crate::name::known::SELF_TYPE | ||
223 | }; | ||
224 | ($ident:ident) => { | ||
225 | $crate::name::known::$ident | ||
226 | }; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | pub use crate::name; | ||