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