]>
Commit | Line | Data |
---|---|---|
9e0c209e SL |
1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use ast; | |
12 | use codemap::{DUMMY_SP, dummy_spanned}; | |
13 | use ext::base::ExtCtxt; | |
14 | use ext::expand::{Expansion, ExpansionKind}; | |
15 | use fold::*; | |
16 | use parse::token::{intern, keywords}; | |
17 | use ptr::P; | |
18 | use util::move_map::MoveMap; | |
19 | use util::small_vector::SmallVector; | |
20 | ||
21 | use std::collections::HashMap; | |
22 | use std::mem; | |
23 | ||
24 | pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { | |
25 | fn mac_placeholder() -> ast::Mac { | |
26 | dummy_spanned(ast::Mac_ { | |
27 | path: ast::Path { span: DUMMY_SP, global: false, segments: Vec::new() }, | |
28 | tts: Vec::new(), | |
29 | }) | |
30 | } | |
31 | ||
32 | let ident = keywords::Invalid.ident(); | |
33 | let attrs = Vec::new(); | |
34 | let vis = ast::Visibility::Inherited; | |
35 | let span = DUMMY_SP; | |
36 | let expr_placeholder = || P(ast::Expr { | |
37 | id: id, span: span, | |
38 | attrs: ast::ThinVec::new(), | |
39 | node: ast::ExprKind::Mac(mac_placeholder()), | |
40 | }); | |
41 | ||
42 | match kind { | |
43 | ExpansionKind::Expr => Expansion::Expr(expr_placeholder()), | |
44 | ExpansionKind::OptExpr => Expansion::OptExpr(Some(expr_placeholder())), | |
45 | ExpansionKind::Items => Expansion::Items(SmallVector::one(P(ast::Item { | |
46 | id: id, span: span, ident: ident, vis: vis, attrs: attrs, | |
47 | node: ast::ItemKind::Mac(mac_placeholder()), | |
48 | }))), | |
49 | ExpansionKind::TraitItems => Expansion::TraitItems(SmallVector::one(ast::TraitItem { | |
50 | id: id, span: span, ident: ident, attrs: attrs, | |
51 | node: ast::TraitItemKind::Macro(mac_placeholder()), | |
52 | })), | |
53 | ExpansionKind::ImplItems => Expansion::ImplItems(SmallVector::one(ast::ImplItem { | |
54 | id: id, span: span, ident: ident, vis: vis, attrs: attrs, | |
55 | node: ast::ImplItemKind::Macro(mac_placeholder()), | |
56 | defaultness: ast::Defaultness::Final, | |
57 | })), | |
58 | ExpansionKind::Pat => Expansion::Pat(P(ast::Pat { | |
59 | id: id, span: span, node: ast::PatKind::Mac(mac_placeholder()), | |
60 | })), | |
61 | ExpansionKind::Ty => Expansion::Ty(P(ast::Ty { | |
62 | id: id, span: span, node: ast::TyKind::Mac(mac_placeholder()), | |
63 | })), | |
64 | ExpansionKind::Stmts => Expansion::Stmts(SmallVector::one({ | |
65 | let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::ThinVec::new())); | |
66 | ast::Stmt { id: id, span: span, node: ast::StmtKind::Mac(mac) } | |
67 | })), | |
68 | } | |
69 | } | |
70 | ||
71 | pub fn macro_scope_placeholder() -> Expansion { | |
72 | placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) | |
73 | } | |
74 | ||
75 | pub struct PlaceholderExpander<'a, 'b: 'a> { | |
76 | expansions: HashMap<ast::NodeId, Expansion>, | |
77 | cx: &'a mut ExtCtxt<'b>, | |
78 | monotonic: bool, | |
79 | } | |
80 | ||
81 | impl<'a, 'b> PlaceholderExpander<'a, 'b> { | |
82 | pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { | |
83 | PlaceholderExpander { | |
84 | cx: cx, | |
85 | expansions: HashMap::new(), | |
86 | monotonic: monotonic, | |
87 | } | |
88 | } | |
89 | ||
90 | pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) { | |
c30ab7b3 | 91 | let expansion = expansion.fold_with(self); |
9e0c209e SL |
92 | self.expansions.insert(id, expansion); |
93 | } | |
94 | ||
c30ab7b3 | 95 | fn remove(&mut self, id: ast::NodeId) -> Expansion { |
9e0c209e SL |
96 | self.expansions.remove(&id).unwrap() |
97 | } | |
98 | } | |
99 | ||
100 | impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { | |
101 | fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> { | |
102 | match item.node { | |
103 | // Scope placeholder | |
104 | ast::ItemKind::Mac(_) if item.id == ast::DUMMY_NODE_ID => SmallVector::one(item), | |
105 | ast::ItemKind::Mac(_) => self.remove(item.id).make_items(), | |
106 | _ => noop_fold_item(item, self), | |
107 | } | |
108 | } | |
109 | ||
110 | fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> { | |
111 | match item.node { | |
112 | ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(), | |
113 | _ => noop_fold_trait_item(item, self), | |
114 | } | |
115 | } | |
116 | ||
117 | fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector<ast::ImplItem> { | |
118 | match item.node { | |
119 | ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(), | |
120 | _ => noop_fold_impl_item(item, self), | |
121 | } | |
122 | } | |
123 | ||
124 | fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> { | |
125 | match expr.node { | |
126 | ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(), | |
127 | _ => expr.map(|expr| noop_fold_expr(expr, self)), | |
128 | } | |
129 | } | |
130 | ||
131 | fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { | |
132 | match expr.node { | |
133 | ast::ExprKind::Mac(_) => self.remove(expr.id).make_opt_expr(), | |
134 | _ => noop_fold_opt_expr(expr, self), | |
135 | } | |
136 | } | |
137 | ||
138 | fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> { | |
139 | let (style, mut expansion) = match stmt.node { | |
140 | ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()), | |
141 | _ => return noop_fold_stmt(stmt, self), | |
142 | }; | |
143 | ||
144 | if style == ast::MacStmtStyle::Semicolon { | |
145 | if let Some(stmt) = expansion.pop() { | |
146 | expansion.push(stmt.add_trailing_semicolon()); | |
147 | } | |
148 | } | |
149 | ||
150 | expansion | |
151 | } | |
152 | ||
153 | fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> { | |
154 | match pat.node { | |
155 | ast::PatKind::Mac(_) => self.remove(pat.id).make_pat(), | |
156 | _ => noop_fold_pat(pat, self), | |
157 | } | |
158 | } | |
159 | ||
160 | fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> { | |
161 | match ty.node { | |
162 | ast::TyKind::Mac(_) => self.remove(ty.id).make_ty(), | |
163 | _ => noop_fold_ty(ty, self), | |
164 | } | |
165 | } | |
166 | ||
167 | fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> { | |
168 | noop_fold_block(block, self).map(|mut block| { | |
169 | let mut macros = Vec::new(); | |
170 | let mut remaining_stmts = block.stmts.len(); | |
171 | ||
172 | block.stmts = block.stmts.move_flat_map(|mut stmt| { | |
173 | remaining_stmts -= 1; | |
174 | ||
175 | // Scope placeholder | |
176 | if let ast::StmtKind::Item(ref item) = stmt.node { | |
177 | if let ast::ItemKind::Mac(..) = item.node { | |
178 | macros.push(item.ident.ctxt.data().outer_mark); | |
179 | return None; | |
180 | } | |
181 | } | |
182 | ||
183 | match stmt.node { | |
184 | // Avoid wasting a node id on a trailing expression statement, | |
185 | // which shares a HIR node with the expression itself. | |
186 | ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id, | |
187 | ||
188 | _ if self.monotonic => { | |
189 | assert_eq!(stmt.id, ast::DUMMY_NODE_ID); | |
190 | stmt.id = self.cx.resolver.next_node_id(); | |
191 | } | |
192 | ||
193 | _ => {} | |
194 | } | |
195 | ||
196 | if self.monotonic && !macros.is_empty() { | |
197 | let macros = mem::replace(&mut macros, Vec::new()); | |
198 | self.cx.resolver.add_expansions_at_stmt(stmt.id, macros); | |
199 | } | |
200 | ||
201 | Some(stmt) | |
202 | }); | |
203 | ||
204 | block | |
205 | }) | |
206 | } | |
207 | ||
208 | fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod { | |
209 | let mut module = noop_fold_mod(module, self); | |
210 | module.items = module.items.move_flat_map(|item| match item.node { | |
211 | ast::ItemKind::Mac(_) => None, // remove scope placeholders from modules | |
212 | _ => Some(item), | |
213 | }); | |
214 | module | |
215 | } | |
216 | } | |
217 | ||
218 | pub fn reconstructed_macro_rules(def: &ast::MacroDef) -> Expansion { | |
219 | Expansion::Items(SmallVector::one(P(ast::Item { | |
220 | ident: def.ident, | |
221 | attrs: def.attrs.clone(), | |
222 | id: ast::DUMMY_NODE_ID, | |
223 | node: ast::ItemKind::Mac(ast::Mac { | |
224 | span: def.span, | |
225 | node: ast::Mac_ { | |
226 | path: ast::Path { | |
227 | span: DUMMY_SP, | |
228 | global: false, | |
229 | segments: vec![ast::PathSegment { | |
230 | identifier: ast::Ident::with_empty_ctxt(intern("macro_rules")), | |
231 | parameters: ast::PathParameters::none(), | |
232 | }], | |
233 | }, | |
234 | tts: def.body.clone(), | |
235 | } | |
236 | }), | |
237 | vis: ast::Visibility::Inherited, | |
238 | span: def.span, | |
239 | }))) | |
240 | } |