]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/ext/placeholders.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / libsyntax / ext / placeholders.rs
CommitLineData
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
11use ast;
12use codemap::{DUMMY_SP, dummy_spanned};
13use ext::base::ExtCtxt;
14use ext::expand::{Expansion, ExpansionKind};
15use fold::*;
16use parse::token::{intern, keywords};
17use ptr::P;
18use util::move_map::MoveMap;
19use util::small_vector::SmallVector;
20
21use std::collections::HashMap;
22use std::mem;
23
24pub 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
71pub fn macro_scope_placeholder() -> Expansion {
72 placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
73}
74
75pub struct PlaceholderExpander<'a, 'b: 'a> {
76 expansions: HashMap<ast::NodeId, Expansion>,
77 cx: &'a mut ExtCtxt<'b>,
78 monotonic: bool,
79}
80
81impl<'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
100impl<'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
218pub 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}