diff options
-rw-r--r-- | crates/ra_hir_expand/src/builtin_macro.rs | 142 |
1 files changed, 124 insertions, 18 deletions
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 4da56529d..d551f9198 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -16,6 +16,31 @@ pub enum BuiltinExpander { | |||
16 | Stringify, | 16 | Stringify, |
17 | } | 17 | } |
18 | 18 | ||
19 | struct BuiltInMacroInfo { | ||
20 | name: name::Name, | ||
21 | kind: BuiltinExpander, | ||
22 | expand: fn( | ||
23 | db: &dyn AstDatabase, | ||
24 | id: MacroCallId, | ||
25 | _tt: &tt::Subtree, | ||
26 | ) -> Result<tt::Subtree, mbe::ExpandError>, | ||
27 | } | ||
28 | |||
29 | macro_rules! register_builtin { | ||
30 | ( $(($name:ident, $kind: ident) => $expand:ident),* ) => { | ||
31 | const BUILTIN_MACROS: &[BuiltInMacroInfo] = &[ | ||
32 | $(BuiltInMacroInfo { name: name::$name, kind: BuiltinExpander::$kind, expand: $expand }),* | ||
33 | ]; | ||
34 | }; | ||
35 | } | ||
36 | |||
37 | register_builtin! { | ||
38 | (COLUMN_MACRO, Column) => column_expand, | ||
39 | (FILE_MACRO, File) => file_expand, | ||
40 | (LINE_MACRO, Line) => line_expand, | ||
41 | (STRINGIFY_MACRO, Stringify) => stringify_expand | ||
42 | } | ||
43 | |||
19 | impl BuiltinExpander { | 44 | impl BuiltinExpander { |
20 | pub fn expand( | 45 | pub fn expand( |
21 | &self, | 46 | &self, |
@@ -23,12 +48,13 @@ impl BuiltinExpander { | |||
23 | id: MacroCallId, | 48 | id: MacroCallId, |
24 | tt: &tt::Subtree, | 49 | tt: &tt::Subtree, |
25 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 50 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
26 | match self { | 51 | let expander = BUILTIN_MACROS |
27 | BuiltinExpander::Column => column_expand(db, id, tt), | 52 | .iter() |
28 | BuiltinExpander::File => file_expand(db, id, tt), | 53 | .find(|it| *self == it.kind) |
29 | BuiltinExpander::Line => line_expand(db, id, tt), | 54 | .map(|it| it.expand) |
30 | BuiltinExpander::Stringify => stringify_expand(db, id, tt), | 55 | .ok_or_else(|| mbe::ExpandError::ConversionError)?; |
31 | } | 56 | |
57 | expander(db, id, tt) | ||
32 | } | 58 | } |
33 | } | 59 | } |
34 | 60 | ||
@@ -37,18 +63,9 @@ pub fn find_builtin_macro( | |||
37 | krate: CrateId, | 63 | krate: CrateId, |
38 | ast_id: AstId<ast::MacroCall>, | 64 | ast_id: AstId<ast::MacroCall>, |
39 | ) -> Option<MacroDefId> { | 65 | ) -> Option<MacroDefId> { |
40 | // FIXME: Better registering method | 66 | let kind = BUILTIN_MACROS.iter().find(|it| *ident == it.name).map(|it| it.kind)?; |
41 | if ident == &name::COLUMN_MACRO { | 67 | |
42 | Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Column) }) | 68 | Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(kind) }) |
43 | } else if ident == &name::FILE_MACRO { | ||
44 | Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::File) }) | ||
45 | } else if ident == &name::LINE_MACRO { | ||
46 | Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Line) }) | ||
47 | } else if ident == &name::STRINGIFY_MACRO { | ||
48 | Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Stringify) }) | ||
49 | } else { | ||
50 | None | ||
51 | } | ||
52 | } | 69 | } |
53 | 70 | ||
54 | fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { | 71 | fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { |
@@ -171,3 +188,92 @@ fn file_expand( | |||
171 | 188 | ||
172 | Ok(expanded) | 189 | Ok(expanded) |
173 | } | 190 | } |
191 | |||
192 | #[cfg(test)] | ||
193 | mod tests { | ||
194 | use super::*; | ||
195 | use crate::{test_db::TestDB, MacroCallLoc}; | ||
196 | use ra_db::{fixture::WithFixture, SourceDatabase}; | ||
197 | |||
198 | fn expand_builtin_macro(s: &str, expander: BuiltinExpander) -> String { | ||
199 | let (db, file_id) = TestDB::with_single_file(&s); | ||
200 | let parsed = db.parse(file_id); | ||
201 | let macro_calls: Vec<_> = | ||
202 | parsed.syntax_node().descendants().filter_map(|it| ast::MacroCall::cast(it)).collect(); | ||
203 | |||
204 | let ast_id_map = db.ast_id_map(file_id.into()); | ||
205 | |||
206 | // the first one should be a macro_rules | ||
207 | let def = MacroDefId { | ||
208 | krate: CrateId(0), | ||
209 | ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0])), | ||
210 | kind: MacroDefKind::BuiltIn(expander), | ||
211 | }; | ||
212 | |||
213 | let loc = MacroCallLoc { | ||
214 | def, | ||
215 | ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[1])), | ||
216 | }; | ||
217 | |||
218 | let id = db.intern_macro(loc); | ||
219 | let parsed = db.parse_or_expand(id.as_file(MacroFileKind::Expr)).unwrap(); | ||
220 | |||
221 | parsed.text().to_string() | ||
222 | } | ||
223 | |||
224 | #[test] | ||
225 | fn test_column_expand() { | ||
226 | let expanded = expand_builtin_macro( | ||
227 | r#" | ||
228 | #[rustc_builtin_macro] | ||
229 | macro_rules! column {() => {}} | ||
230 | column!() | ||
231 | "#, | ||
232 | BuiltinExpander::Column, | ||
233 | ); | ||
234 | |||
235 | assert_eq!(expanded, "9"); | ||
236 | } | ||
237 | |||
238 | #[test] | ||
239 | fn test_line_expand() { | ||
240 | let expanded = expand_builtin_macro( | ||
241 | r#" | ||
242 | #[rustc_builtin_macro] | ||
243 | macro_rules! line {() => {}} | ||
244 | line!() | ||
245 | "#, | ||
246 | BuiltinExpander::Line, | ||
247 | ); | ||
248 | |||
249 | assert_eq!(expanded, "4"); | ||
250 | } | ||
251 | |||
252 | #[test] | ||
253 | fn test_stringify_expand() { | ||
254 | let expanded = expand_builtin_macro( | ||
255 | r#" | ||
256 | #[rustc_builtin_macro] | ||
257 | macro_rules! stringify {() => {}} | ||
258 | stringify!(a b c) | ||
259 | "#, | ||
260 | BuiltinExpander::Stringify, | ||
261 | ); | ||
262 | |||
263 | assert_eq!(expanded, "\"a b c\""); | ||
264 | } | ||
265 | |||
266 | #[test] | ||
267 | fn test_file_expand() { | ||
268 | let expanded = expand_builtin_macro( | ||
269 | r#" | ||
270 | #[rustc_builtin_macro] | ||
271 | macro_rules! file {() => {}} | ||
272 | file!() | ||
273 | "#, | ||
274 | BuiltinExpander::File, | ||
275 | ); | ||
276 | |||
277 | assert_eq!(expanded, "\"\""); | ||
278 | } | ||
279 | } | ||