aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand/src/db.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand/src/db.rs')
-rw-r--r--crates/hir_expand/src/db.rs119
1 files changed, 81 insertions, 38 deletions
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index fc73e435b..c0ab70b60 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -3,9 +3,15 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use base_db::{salsa, SourceDatabase}; 5use base_db::{salsa, SourceDatabase};
6use mbe::{ExpandError, ExpandResult, MacroRules}; 6use mbe::{ExpandError, ExpandResult, MacroDef, MacroRules};
7use parser::FragmentKind; 7use parser::FragmentKind;
8use syntax::{algo::diff, ast::NameOwner, AstNode, GreenNode, Parse, SyntaxKind::*, SyntaxNode}; 8use syntax::{
9 algo::diff,
10 ast::{MacroStmts, NameOwner},
11 AstNode, GreenNode, Parse,
12 SyntaxKind::*,
13 SyntaxNode,
14};
9 15
10use crate::{ 16use crate::{
11 ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, 17 ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander,
@@ -22,6 +28,7 @@ const TOKEN_LIMIT: usize = 524288;
22#[derive(Debug, Clone, Eq, PartialEq)] 28#[derive(Debug, Clone, Eq, PartialEq)]
23pub enum TokenExpander { 29pub enum TokenExpander {
24 MacroRules(mbe::MacroRules), 30 MacroRules(mbe::MacroRules),
31 MacroDef(mbe::MacroDef),
25 Builtin(BuiltinFnLikeExpander), 32 Builtin(BuiltinFnLikeExpander),
26 BuiltinDerive(BuiltinDeriveExpander), 33 BuiltinDerive(BuiltinDeriveExpander),
27 ProcMacro(ProcMacroExpander), 34 ProcMacro(ProcMacroExpander),
@@ -36,6 +43,7 @@ impl TokenExpander {
36 ) -> mbe::ExpandResult<tt::Subtree> { 43 ) -> mbe::ExpandResult<tt::Subtree> {
37 match self { 44 match self {
38 TokenExpander::MacroRules(it) => it.expand(tt), 45 TokenExpander::MacroRules(it) => it.expand(tt),
46 TokenExpander::MacroDef(it) => it.expand(tt),
39 TokenExpander::Builtin(it) => it.expand(db, id, tt), 47 TokenExpander::Builtin(it) => it.expand(db, id, tt),
40 // FIXME switch these to ExpandResult as well 48 // FIXME switch these to ExpandResult as well
41 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(), 49 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt).into(),
@@ -51,6 +59,7 @@ impl TokenExpander {
51 pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { 59 pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId {
52 match self { 60 match self {
53 TokenExpander::MacroRules(it) => it.map_id_down(id), 61 TokenExpander::MacroRules(it) => it.map_id_down(id),
62 TokenExpander::MacroDef(it) => it.map_id_down(id),
54 TokenExpander::Builtin(..) => id, 63 TokenExpander::Builtin(..) => id,
55 TokenExpander::BuiltinDerive(..) => id, 64 TokenExpander::BuiltinDerive(..) => id,
56 TokenExpander::ProcMacro(..) => id, 65 TokenExpander::ProcMacro(..) => id,
@@ -60,6 +69,7 @@ impl TokenExpander {
60 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { 69 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
61 match self { 70 match self {
62 TokenExpander::MacroRules(it) => it.map_id_up(id), 71 TokenExpander::MacroRules(it) => it.map_id_up(id),
72 TokenExpander::MacroDef(it) => it.map_id_up(id),
63 TokenExpander::Builtin(..) => (id, mbe::Origin::Call), 73 TokenExpander::Builtin(..) => (id, mbe::Origin::Call),
64 TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call), 74 TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call),
65 TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call), 75 TokenExpander::ProcMacro(..) => (id, mbe::Origin::Call),
@@ -130,26 +140,40 @@ fn ast_id_map(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<AstIdMap> {
130 140
131fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { 141fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
132 match id.kind { 142 match id.kind {
133 MacroDefKind::Declarative(ast_id) => { 143 MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) {
134 let macro_rules = match ast_id.to_node(db) { 144 syntax::ast::Macro::MacroRules(macro_rules) => {
135 syntax::ast::Macro::MacroRules(mac) => mac, 145 let arg = macro_rules.token_tree()?;
136 syntax::ast::Macro::MacroDef(_) => return None, 146 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
137 }; 147 log::warn!("fail on macro_rules to token tree: {:#?}", arg);
138 let arg = macro_rules.token_tree()?; 148 None
139 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { 149 })?;
140 log::warn!("fail on macro_def to token tree: {:#?}", arg); 150 let rules = match MacroRules::parse(&tt) {
141 None 151 Ok(it) => it,
142 })?; 152 Err(err) => {
143 let rules = match MacroRules::parse(&tt) { 153 let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default();
144 Ok(it) => it, 154 log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt);
145 Err(err) => { 155 return None;
146 let name = macro_rules.name().map(|n| n.to_string()).unwrap_or_default(); 156 }
147 log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt); 157 };
148 return None; 158 Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
149 } 159 }
150 }; 160 syntax::ast::Macro::MacroDef(macro_def) => {
151 Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) 161 let arg = macro_def.body()?;
152 } 162 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
163 log::warn!("fail on macro_def to token tree: {:#?}", arg);
164 None
165 })?;
166 let rules = match MacroDef::parse(&tt) {
167 Ok(it) => it,
168 Err(err) => {
169 let name = macro_def.name().map(|n| n.to_string()).unwrap_or_default();
170 log::warn!("fail on macro_def parse ({}): {:?} {:#?}", name, err, tt);
171 return None;
172 }
173 };
174 Some(Arc::new((TokenExpander::MacroDef(rules), tmap)))
175 }
176 },
153 MacroDefKind::BuiltIn(expander, _) => { 177 MacroDefKind::BuiltIn(expander, _) => {
154 Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default()))) 178 Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default())))
155 } 179 }
@@ -340,13 +364,19 @@ fn parse_macro_with_arg(
340 None => return ExpandResult { value: None, err: result.err }, 364 None => return ExpandResult { value: None, err: result.err },
341 }; 365 };
342 366
343 log::debug!("expanded = {}", tt.as_debug_string());
344
345 let fragment_kind = to_fragment_kind(db, macro_call_id); 367 let fragment_kind = to_fragment_kind(db, macro_call_id);
346 368
369 log::debug!("expanded = {}", tt.as_debug_string());
370 log::debug!("kind = {:?}", fragment_kind);
371
347 let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) { 372 let (parse, rev_token_map) = match mbe::token_tree_to_syntax_node(&tt, fragment_kind) {
348 Ok(it) => it, 373 Ok(it) => it,
349 Err(err) => { 374 Err(err) => {
375 log::debug!(
376 "failed to parse expanstion to {:?} = {}",
377 fragment_kind,
378 tt.as_debug_string()
379 );
350 return ExpandResult::only_err(err); 380 return ExpandResult::only_err(err);
351 } 381 }
352 }; 382 };
@@ -362,15 +392,34 @@ fn parse_macro_with_arg(
362 return ExpandResult::only_err(err); 392 return ExpandResult::only_err(err);
363 } 393 }
364 }; 394 };
365 395 if is_self_replicating(&node, &call_node.value) {
366 if !diff(&node, &call_node.value).is_empty() {
367 ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) }
368 } else {
369 return ExpandResult::only_err(err); 396 return ExpandResult::only_err(err);
397 } else {
398 ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: Some(err) }
399 }
400 }
401 None => {
402 log::debug!("parse = {:?}", parse.syntax_node().kind());
403 ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None }
404 }
405 }
406}
407
408fn is_self_replicating(from: &SyntaxNode, to: &SyntaxNode) -> bool {
409 if diff(from, to).is_empty() {
410 return true;
411 }
412 if let Some(stmts) = MacroStmts::cast(from.clone()) {
413 if stmts.statements().any(|stmt| diff(stmt.syntax(), to).is_empty()) {
414 return true;
415 }
416 if let Some(expr) = stmts.expr() {
417 if diff(expr.syntax(), to).is_empty() {
418 return true;
370 } 419 }
371 } 420 }
372 None => ExpandResult { value: Some((parse, Arc::new(rev_token_map))), err: None },
373 } 421 }
422 false
374} 423}
375 424
376fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> { 425fn hygiene_frame(db: &dyn AstDatabase, file_id: HirFileId) -> Arc<HygieneFrame> {
@@ -390,21 +439,15 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
390 439
391 let parent = match syn.parent() { 440 let parent = match syn.parent() {
392 Some(it) => it, 441 Some(it) => it,
393 None => { 442 None => return FragmentKind::Statements,
394 // FIXME:
395 // If it is root, which means the parent HirFile
396 // MacroKindFile must be non-items
397 // return expr now.
398 return FragmentKind::Expr;
399 }
400 }; 443 };
401 444
402 match parent.kind() { 445 match parent.kind() {
403 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, 446 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
404 MACRO_STMTS => FragmentKind::Statement, 447 MACRO_STMTS => FragmentKind::Statements,
405 ITEM_LIST => FragmentKind::Items, 448 ITEM_LIST => FragmentKind::Items,
406 LET_STMT => { 449 LET_STMT => {
407 // FIXME: Handle Pattern 450 // FIXME: Handle LHS Pattern
408 FragmentKind::Expr 451 FragmentKind::Expr
409 } 452 }
410 EXPR_STMT => FragmentKind::Statements, 453 EXPR_STMT => FragmentKind::Statements,