]>
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}; | |
32a655c1 | 15 | use ext::hygiene::Mark; |
8bb4bdeb | 16 | use tokenstream::TokenStream; |
9e0c209e | 17 | use fold::*; |
9e0c209e | 18 | use ptr::P; |
32a655c1 | 19 | use symbol::keywords; |
9e0c209e SL |
20 | use util::move_map::MoveMap; |
21 | use util::small_vector::SmallVector; | |
22 | ||
23 | use std::collections::HashMap; | |
9e0c209e SL |
24 | |
25 | pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion { | |
26 | fn mac_placeholder() -> ast::Mac { | |
27 | dummy_spanned(ast::Mac_ { | |
32a655c1 | 28 | path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, |
8bb4bdeb | 29 | tts: TokenStream::empty().into(), |
9e0c209e SL |
30 | }) |
31 | } | |
32 | ||
33 | let ident = keywords::Invalid.ident(); | |
34 | let attrs = Vec::new(); | |
35 | let vis = ast::Visibility::Inherited; | |
36 | let span = DUMMY_SP; | |
37 | let expr_placeholder = || P(ast::Expr { | |
38 | id: id, span: span, | |
39 | attrs: ast::ThinVec::new(), | |
40 | node: ast::ExprKind::Mac(mac_placeholder()), | |
41 | }); | |
42 | ||
43 | match kind { | |
44 | ExpansionKind::Expr => Expansion::Expr(expr_placeholder()), | |
45 | ExpansionKind::OptExpr => Expansion::OptExpr(Some(expr_placeholder())), | |
46 | ExpansionKind::Items => Expansion::Items(SmallVector::one(P(ast::Item { | |
47 | id: id, span: span, ident: ident, vis: vis, attrs: attrs, | |
48 | node: ast::ItemKind::Mac(mac_placeholder()), | |
49 | }))), | |
50 | ExpansionKind::TraitItems => Expansion::TraitItems(SmallVector::one(ast::TraitItem { | |
51 | id: id, span: span, ident: ident, attrs: attrs, | |
52 | node: ast::TraitItemKind::Macro(mac_placeholder()), | |
53 | })), | |
54 | ExpansionKind::ImplItems => Expansion::ImplItems(SmallVector::one(ast::ImplItem { | |
55 | id: id, span: span, ident: ident, vis: vis, attrs: attrs, | |
56 | node: ast::ImplItemKind::Macro(mac_placeholder()), | |
57 | defaultness: ast::Defaultness::Final, | |
58 | })), | |
59 | ExpansionKind::Pat => Expansion::Pat(P(ast::Pat { | |
60 | id: id, span: span, node: ast::PatKind::Mac(mac_placeholder()), | |
61 | })), | |
62 | ExpansionKind::Ty => Expansion::Ty(P(ast::Ty { | |
63 | id: id, span: span, node: ast::TyKind::Mac(mac_placeholder()), | |
64 | })), | |
65 | ExpansionKind::Stmts => Expansion::Stmts(SmallVector::one({ | |
66 | let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::ThinVec::new())); | |
67 | ast::Stmt { id: id, span: span, node: ast::StmtKind::Mac(mac) } | |
68 | })), | |
69 | } | |
70 | } | |
71 | ||
9e0c209e SL |
72 | pub struct PlaceholderExpander<'a, 'b: 'a> { |
73 | expansions: HashMap<ast::NodeId, Expansion>, | |
74 | cx: &'a mut ExtCtxt<'b>, | |
75 | monotonic: bool, | |
76 | } | |
77 | ||
78 | impl<'a, 'b> PlaceholderExpander<'a, 'b> { | |
79 | pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { | |
80 | PlaceholderExpander { | |
81 | cx: cx, | |
82 | expansions: HashMap::new(), | |
83 | monotonic: monotonic, | |
84 | } | |
85 | } | |
86 | ||
8bb4bdeb XL |
87 | pub fn add(&mut self, id: ast::NodeId, expansion: Expansion, derives: Vec<Mark>) { |
88 | let mut expansion = expansion.fold_with(self); | |
89 | if let Expansion::Items(mut items) = expansion { | |
90 | for derive in derives { | |
91 | match self.remove(derive.as_placeholder_id()) { | |
92 | Expansion::Items(derived_items) => items.extend(derived_items), | |
93 | _ => unreachable!(), | |
94 | } | |
95 | } | |
96 | expansion = Expansion::Items(items); | |
97 | } | |
9e0c209e SL |
98 | self.expansions.insert(id, expansion); |
99 | } | |
100 | ||
c30ab7b3 | 101 | fn remove(&mut self, id: ast::NodeId) -> Expansion { |
9e0c209e SL |
102 | self.expansions.remove(&id).unwrap() |
103 | } | |
104 | } | |
105 | ||
106 | impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { | |
107 | fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> { | |
108 | match item.node { | |
32a655c1 | 109 | ast::ItemKind::Mac(_) => return self.remove(item.id).make_items(), |
8bb4bdeb | 110 | ast::ItemKind::MacroDef(_) => return SmallVector::one(item), |
32a655c1 | 111 | _ => {} |
9e0c209e | 112 | } |
32a655c1 SL |
113 | |
114 | noop_fold_item(item, self) | |
9e0c209e SL |
115 | } |
116 | ||
117 | fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> { | |
118 | match item.node { | |
119 | ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(), | |
120 | _ => noop_fold_trait_item(item, self), | |
121 | } | |
122 | } | |
123 | ||
124 | fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector<ast::ImplItem> { | |
125 | match item.node { | |
126 | ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(), | |
127 | _ => noop_fold_impl_item(item, self), | |
128 | } | |
129 | } | |
130 | ||
131 | fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> { | |
132 | match expr.node { | |
133 | ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(), | |
134 | _ => expr.map(|expr| noop_fold_expr(expr, self)), | |
135 | } | |
136 | } | |
137 | ||
138 | fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> { | |
139 | match expr.node { | |
140 | ast::ExprKind::Mac(_) => self.remove(expr.id).make_opt_expr(), | |
141 | _ => noop_fold_opt_expr(expr, self), | |
142 | } | |
143 | } | |
144 | ||
145 | fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> { | |
146 | let (style, mut expansion) = match stmt.node { | |
147 | ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()), | |
148 | _ => return noop_fold_stmt(stmt, self), | |
149 | }; | |
150 | ||
151 | if style == ast::MacStmtStyle::Semicolon { | |
152 | if let Some(stmt) = expansion.pop() { | |
153 | expansion.push(stmt.add_trailing_semicolon()); | |
154 | } | |
155 | } | |
156 | ||
157 | expansion | |
158 | } | |
159 | ||
160 | fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> { | |
161 | match pat.node { | |
162 | ast::PatKind::Mac(_) => self.remove(pat.id).make_pat(), | |
163 | _ => noop_fold_pat(pat, self), | |
164 | } | |
165 | } | |
166 | ||
167 | fn fold_ty(&mut self, ty: P<ast::Ty>) -> P<ast::Ty> { | |
168 | match ty.node { | |
169 | ast::TyKind::Mac(_) => self.remove(ty.id).make_ty(), | |
170 | _ => noop_fold_ty(ty, self), | |
171 | } | |
172 | } | |
173 | ||
174 | fn fold_block(&mut self, block: P<ast::Block>) -> P<ast::Block> { | |
175 | noop_fold_block(block, self).map(|mut block| { | |
9e0c209e SL |
176 | let mut remaining_stmts = block.stmts.len(); |
177 | ||
178 | block.stmts = block.stmts.move_flat_map(|mut stmt| { | |
179 | remaining_stmts -= 1; | |
180 | ||
9e0c209e SL |
181 | match stmt.node { |
182 | // Avoid wasting a node id on a trailing expression statement, | |
183 | // which shares a HIR node with the expression itself. | |
184 | ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id, | |
185 | ||
186 | _ if self.monotonic => { | |
187 | assert_eq!(stmt.id, ast::DUMMY_NODE_ID); | |
188 | stmt.id = self.cx.resolver.next_node_id(); | |
189 | } | |
190 | ||
191 | _ => {} | |
192 | } | |
193 | ||
9e0c209e SL |
194 | Some(stmt) |
195 | }); | |
196 | ||
197 | block | |
198 | }) | |
199 | } | |
200 | ||
201 | fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod { | |
202 | let mut module = noop_fold_mod(module, self); | |
203 | module.items = module.items.move_flat_map(|item| match item.node { | |
32a655c1 | 204 | ast::ItemKind::Mac(_) if !self.cx.ecfg.keep_macs => None, // remove macro definitions |
9e0c209e SL |
205 | _ => Some(item), |
206 | }); | |
207 | module | |
208 | } | |
9e0c209e | 209 | |
32a655c1 SL |
210 | fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { |
211 | mac | |
212 | } | |
9e0c209e | 213 | } |