aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_expand/src/lib.rs
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-12-05 14:10:33 +0000
committerFlorian Diebold <[email protected]>2019-12-05 16:23:09 +0000
commit18f6a995d0fc1f45099f3cc810a5d55d5401b41b (patch)
tree808cb0f025b488f59935007802d1bb85f1cf0044 /crates/ra_hir_expand/src/lib.rs
parent4c0bd068da39e74c66104206e27c270454e3562e (diff)
Add expansion infrastructure for derive macros
Diffstat (limited to 'crates/ra_hir_expand/src/lib.rs')
-rw-r--r--crates/ra_hir_expand/src/lib.rs76
1 files changed, 52 insertions, 24 deletions
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index 3be9bdf86..59c69b91b 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -9,6 +9,7 @@ pub mod ast_id_map;
9pub mod name; 9pub mod name;
10pub mod hygiene; 10pub mod hygiene;
11pub mod diagnostics; 11pub mod diagnostics;
12pub mod builtin_derive;
12pub mod builtin_macro; 13pub mod builtin_macro;
13pub mod quote; 14pub mod quote;
14 15
@@ -23,6 +24,7 @@ use ra_syntax::{
23}; 24};
24 25
25use crate::ast_id_map::FileAstId; 26use crate::ast_id_map::FileAstId;
27use crate::builtin_derive::BuiltinDeriveExpander;
26use crate::builtin_macro::BuiltinFnLikeExpander; 28use crate::builtin_macro::BuiltinFnLikeExpander;
27 29
28#[cfg(test)] 30#[cfg(test)]
@@ -69,7 +71,7 @@ impl HirFileId {
69 HirFileIdRepr::FileId(file_id) => file_id, 71 HirFileIdRepr::FileId(file_id) => file_id,
70 HirFileIdRepr::MacroFile(macro_file) => { 72 HirFileIdRepr::MacroFile(macro_file) => {
71 let loc = db.lookup_intern_macro(macro_file.macro_call_id); 73 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
72 loc.ast_id.file_id.original_file(db) 74 loc.kind.file_id().original_file(db)
73 } 75 }
74 } 76 }
75 } 77 }
@@ -81,8 +83,8 @@ impl HirFileId {
81 HirFileIdRepr::MacroFile(macro_file) => { 83 HirFileIdRepr::MacroFile(macro_file) => {
82 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); 84 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
83 85
84 let arg_tt = loc.ast_id.to_node(db).token_tree()?; 86 let arg_tt = loc.kind.arg(db)?;
85 let def_tt = loc.def.ast_id.to_node(db).token_tree()?; 87 let def_tt = loc.def.ast_id?.to_node(db).token_tree()?;
86 88
87 let macro_def = db.macro_def(loc.def)?; 89 let macro_def = db.macro_def(loc.def)?;
88 let (parse, exp_map) = db.parse_macro(macro_file)?; 90 let (parse, exp_map) = db.parse_macro(macro_file)?;
@@ -90,8 +92,8 @@ impl HirFileId {
90 92
91 Some(ExpansionInfo { 93 Some(ExpansionInfo {
92 expanded: InFile::new(self, parse.syntax_node()), 94 expanded: InFile::new(self, parse.syntax_node()),
93 arg: InFile::new(loc.ast_id.file_id, arg_tt), 95 arg: InFile::new(loc.kind.file_id(), arg_tt),
94 def: InFile::new(loc.ast_id.file_id, def_tt), 96 def: InFile::new(loc.def.ast_id?.file_id, def_tt),
95 macro_arg, 97 macro_arg,
96 macro_def, 98 macro_def,
97 exp_map, 99 exp_map,
@@ -129,18 +131,20 @@ impl salsa::InternKey for MacroCallId {
129 131
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 132#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
131pub struct MacroDefId { 133pub struct MacroDefId {
132 pub krate: CrateId, 134 // FIXME: krate and ast_id are currently optional because we don't have a
133 pub ast_id: AstId<ast::MacroCall>, 135 // definition location for built-in derives. There is one, though: the
136 // standard library defines them. The problem is that it uses the new
137 // `macro` syntax for this, which we don't support yet. As soon as we do
138 // (which will probably require touching this code), we can instead use
139 // that (and also remove the hacks for resolving built-in derives).
140 pub krate: Option<CrateId>,
141 pub ast_id: Option<AstId<ast::MacroCall>>,
134 pub kind: MacroDefKind, 142 pub kind: MacroDefKind,
135} 143}
136 144
137impl MacroDefId { 145impl MacroDefId {
138 pub fn as_call_id( 146 pub fn as_call_id(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> MacroCallId {
139 self, 147 db.intern_macro(MacroCallLoc { def: self, kind })
140 db: &dyn db::AstDatabase,
141 ast_id: AstId<ast::MacroCall>,
142 ) -> MacroCallId {
143 db.intern_macro(MacroCallLoc { def: self, ast_id })
144 } 148 }
145} 149}
146 150
@@ -148,12 +152,38 @@ impl MacroDefId {
148pub enum MacroDefKind { 152pub enum MacroDefKind {
149 Declarative, 153 Declarative,
150 BuiltIn(BuiltinFnLikeExpander), 154 BuiltIn(BuiltinFnLikeExpander),
155 // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
156 BuiltInDerive(BuiltinDeriveExpander),
151} 157}
152 158
153#[derive(Debug, Clone, PartialEq, Eq, Hash)] 159#[derive(Debug, Clone, PartialEq, Eq, Hash)]
154pub struct MacroCallLoc { 160pub struct MacroCallLoc {
155 pub(crate) def: MacroDefId, 161 pub(crate) def: MacroDefId,
156 pub(crate) ast_id: AstId<ast::MacroCall>, 162 pub(crate) kind: MacroCallKind,
163}
164
165#[derive(Debug, Clone, PartialEq, Eq, Hash)]
166pub enum MacroCallKind {
167 FnLike(AstId<ast::MacroCall>),
168 Attr(AstId<ast::ModuleItem>),
169}
170
171impl MacroCallKind {
172 pub fn file_id(&self) -> HirFileId {
173 match self {
174 MacroCallKind::FnLike(ast_id) => ast_id.file_id,
175 MacroCallKind::Attr(ast_id) => ast_id.file_id,
176 }
177 }
178
179 pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
180 match self {
181 MacroCallKind::FnLike(ast_id) => {
182 Some(ast_id.to_node(db).token_tree()?.syntax().clone())
183 }
184 MacroCallKind::Attr(ast_id) => Some(ast_id.to_node(db).syntax().clone()),
185 }
186 }
157} 187}
158 188
159impl MacroCallId { 189impl MacroCallId {
@@ -167,7 +197,7 @@ impl MacroCallId {
167#[derive(Debug, Clone, PartialEq, Eq)] 197#[derive(Debug, Clone, PartialEq, Eq)]
168pub struct ExpansionInfo { 198pub struct ExpansionInfo {
169 expanded: InFile<SyntaxNode>, 199 expanded: InFile<SyntaxNode>,
170 arg: InFile<ast::TokenTree>, 200 arg: InFile<SyntaxNode>,
171 def: InFile<ast::TokenTree>, 201 def: InFile<ast::TokenTree>,
172 202
173 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, 203 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
@@ -178,8 +208,7 @@ pub struct ExpansionInfo {
178impl ExpansionInfo { 208impl ExpansionInfo {
179 pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> { 209 pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> {
180 assert_eq!(token.file_id, self.arg.file_id); 210 assert_eq!(token.file_id, self.arg.file_id);
181 let range = 211 let range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?;
182 token.value.text_range().checked_sub(self.arg.value.syntax().text_range().start())?;
183 let token_id = self.macro_arg.1.token_by_range(range)?; 212 let token_id = self.macro_arg.1.token_by_range(range)?;
184 let token_id = self.macro_def.0.map_id_down(token_id); 213 let token_id = self.macro_def.0.map_id_down(token_id);
185 214
@@ -195,16 +224,15 @@ impl ExpansionInfo {
195 224
196 let (token_id, origin) = self.macro_def.0.map_id_up(token_id); 225 let (token_id, origin) = self.macro_def.0.map_id_up(token_id);
197 let (token_map, tt) = match origin { 226 let (token_map, tt) = match origin {
198 mbe::Origin::Call => (&self.macro_arg.1, &self.arg), 227 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
199 mbe::Origin::Def => (&self.macro_def.1, &self.def), 228 mbe::Origin::Def => {
229 (&self.macro_def.1, self.def.as_ref().map(|tt| tt.syntax().clone()))
230 }
200 }; 231 };
201 232
202 let range = token_map.range_by_token(token_id)?; 233 let range = token_map.range_by_token(token_id)?;
203 let token = algo::find_covering_element( 234 let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start())
204 tt.value.syntax(), 235 .into_token()?;
205 range + tt.value.syntax().text_range().start(),
206 )
207 .into_token()?;
208 Some(tt.with_value(token)) 236 Some(tt.with_value(token))
209 } 237 }
210} 238}