1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use rustc_data_structures::sync::Lrc;
use std::collections::HashMap;
use syntax::ast::*;
use syntax::parse::token::{Nonterminal, Token};
use syntax::source_map::Span;
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::visit::{self, Visitor};
use crate::ast_manip::{AstEquiv, ListNodeIds, Visit};
use crate::node_map::NodeMap;
use super::mac_table::{InvocKind, MacTable};
pub fn match_nonterminal_ids(node_map: &mut NodeMap, mac_table: &MacTable) {
for info in mac_table.invocations() {
let mac = match info.invoc {
InvocKind::Mac(mac) => mac,
_ => continue,
};
let mut span_map = HashMap::new();
collect_nonterminals(mac.node.tts.clone().into(), &mut span_map);
let mut v = NtUseVisitor {
nts: &span_map,
matched_ids: Vec::new(),
};
info.expanded.visit(&mut v);
node_map.add_edges(&v.matched_ids);
}
}
fn nt_span(nt: &Nonterminal) -> Option<Span> {
use syntax::parse::token::Nonterminal::*;
Some(match nt {
NtItem(ref i) => i.span,
NtBlock(ref b) => b.span,
NtStmt(ref s) => s.span,
NtPat(ref p) => p.span,
NtExpr(ref e) => e.span,
NtTy(ref t) => t.span,
NtImplItem(ref ii) => ii.span,
NtTraitItem(ref ti) => ti.span,
NtForeignItem(ref fi) => fi.span,
_ => return None,
})
}
fn collect_nonterminals(ts: TokenStream, span_map: &mut HashMap<Span, Lrc<Nonterminal>>) {
for tt in ts.into_trees() {
match tt {
TokenTree::Token(_, Token::Interpolated(nt)) => {
if let Some(span) = nt_span(&nt) {
span_map.insert(span, nt.clone());
}
}
TokenTree::Token(..) => {}
TokenTree::Delimited(_, _, tts) => {
collect_nonterminals(tts.into(), span_map);
}
}
}
}
struct NtUseVisitor<'a> {
nts: &'a HashMap<Span, Lrc<Nonterminal>>,
matched_ids: Vec<(NodeId, NodeId)>,
}
macro_rules! define_nt_use_visitor {
($( $visit_thing:ident, $walk_thing:ident, $NtThing:ident, $Thing:ty; )*) => {
impl<'a, 'ast> Visitor<'ast> for NtUseVisitor<'a> {
$( fn $visit_thing(&mut self, x: &'ast $Thing) {
if let Some(nt) = self.nts.get(&x.span) {
match **nt {
Nonterminal::$NtThing(ref y) => {
if AstEquiv::ast_equiv(x, y) {
self.matched_ids.extend(
x.list_node_ids().into_iter().zip(
y.list_node_ids().into_iter()));
return;
}
},
_ => {},
}
}
visit::$walk_thing(self, x);
} )*
}
};
}
define_nt_use_visitor! {
visit_item, walk_item, NtItem, Item;
visit_block, walk_block, NtBlock, Block;
visit_stmt, walk_stmt, NtStmt, Stmt;
visit_pat, walk_pat, NtPat, Pat;
visit_expr, walk_expr, NtExpr, Expr;
visit_ty, walk_ty, NtTy, Ty;
visit_impl_item, walk_impl_item, NtImplItem, ImplItem;
visit_trait_item, walk_trait_item, NtTraitItem, TraitItem;
visit_foreign_item, walk_foreign_item, NtForeignItem, ForeignItem;
}