]>
Commit | Line | Data |
---|---|---|
c34b1796 | 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
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 | ||
3b2f2976 | 11 | pub use self::SyntaxExtension::*; |
1a4d82fc | 12 | |
8bb4bdeb | 13 | use ast::{self, Attribute, Name, PatKind, MetaItem}; |
3157f602 | 14 | use attr::HasAttrs; |
cc61c64b | 15 | use codemap::{self, CodeMap, Spanned, respan}; |
2c00a5a8 | 16 | use syntax_pos::{Span, MultiSpan, DUMMY_SP}; |
83c7162d | 17 | use errors::{DiagnosticBuilder, DiagnosticId}; |
8bb4bdeb | 18 | use ext::expand::{self, Expansion, Invocation}; |
cc61c64b | 19 | use ext::hygiene::{Mark, SyntaxContext}; |
9e0c209e | 20 | use fold::{self, Folder}; |
476ff2be | 21 | use parse::{self, parser, DirectoryOwnership}; |
223e47cc | 22 | use parse::token; |
1a4d82fc | 23 | use ptr::P; |
ff7c6d11 | 24 | use symbol::{keywords, Ident, Symbol}; |
1a4d82fc | 25 | use util::small_vector::SmallVector; |
1a4d82fc | 26 | |
7cac9316 | 27 | use std::collections::HashMap; |
ff7c6d11 | 28 | use std::iter; |
9e0c209e | 29 | use std::path::PathBuf; |
1a4d82fc | 30 | use std::rc::Rc; |
83c7162d | 31 | use rustc_data_structures::sync::{self, Lrc}; |
c34b1796 | 32 | use std::default::Default; |
9e0c209e | 33 | use tokenstream::{self, TokenStream}; |
1a4d82fc | 34 | |
223e47cc | 35 | |
85aaf69f SL |
36 | #[derive(Debug,Clone)] |
37 | pub enum Annotatable { | |
38 | Item(P<ast::Item>), | |
c34b1796 AL |
39 | TraitItem(P<ast::TraitItem>), |
40 | ImplItem(P<ast::ImplItem>), | |
83c7162d | 41 | ForeignItem(P<ast::ForeignItem>), |
0531ce1d XL |
42 | Stmt(P<ast::Stmt>), |
43 | Expr(P<ast::Expr>), | |
85aaf69f SL |
44 | } |
45 | ||
3157f602 | 46 | impl HasAttrs for Annotatable { |
9e0c209e | 47 | fn attrs(&self) -> &[Attribute] { |
85aaf69f | 48 | match *self { |
3157f602 XL |
49 | Annotatable::Item(ref item) => &item.attrs, |
50 | Annotatable::TraitItem(ref trait_item) => &trait_item.attrs, | |
51 | Annotatable::ImplItem(ref impl_item) => &impl_item.attrs, | |
83c7162d | 52 | Annotatable::ForeignItem(ref foreign_item) => &foreign_item.attrs, |
0531ce1d XL |
53 | Annotatable::Stmt(ref stmt) => stmt.attrs(), |
54 | Annotatable::Expr(ref expr) => &expr.attrs, | |
85aaf69f SL |
55 | } |
56 | } | |
57 | ||
9e0c209e | 58 | fn map_attrs<F: FnOnce(Vec<Attribute>) -> Vec<Attribute>>(self, f: F) -> Self { |
85aaf69f | 59 | match self { |
3157f602 XL |
60 | Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)), |
61 | Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)), | |
62 | Annotatable::ImplItem(impl_item) => Annotatable::ImplItem(impl_item.map_attrs(f)), | |
83c7162d XL |
63 | Annotatable::ForeignItem(foreign_item) => |
64 | Annotatable::ForeignItem(foreign_item.map_attrs(f)), | |
0531ce1d XL |
65 | Annotatable::Stmt(stmt) => Annotatable::Stmt(stmt.map_attrs(f)), |
66 | Annotatable::Expr(expr) => Annotatable::Expr(expr.map_attrs(f)), | |
85aaf69f SL |
67 | } |
68 | } | |
3157f602 XL |
69 | } |
70 | ||
71 | impl Annotatable { | |
cc61c64b XL |
72 | pub fn span(&self) -> Span { |
73 | match *self { | |
74 | Annotatable::Item(ref item) => item.span, | |
75 | Annotatable::TraitItem(ref trait_item) => trait_item.span, | |
76 | Annotatable::ImplItem(ref impl_item) => impl_item.span, | |
83c7162d | 77 | Annotatable::ForeignItem(ref foreign_item) => foreign_item.span, |
0531ce1d XL |
78 | Annotatable::Stmt(ref stmt) => stmt.span, |
79 | Annotatable::Expr(ref expr) => expr.span, | |
cc61c64b XL |
80 | } |
81 | } | |
82 | ||
85aaf69f SL |
83 | pub fn expect_item(self) -> P<ast::Item> { |
84 | match self { | |
85 | Annotatable::Item(i) => i, | |
86 | _ => panic!("expected Item") | |
87 | } | |
88 | } | |
89 | ||
d9579d0f AL |
90 | pub fn map_item_or<F, G>(self, mut f: F, mut or: G) -> Annotatable |
91 | where F: FnMut(P<ast::Item>) -> P<ast::Item>, | |
92 | G: FnMut(Annotatable) -> Annotatable | |
93 | { | |
94 | match self { | |
95 | Annotatable::Item(i) => Annotatable::Item(f(i)), | |
96 | _ => or(self) | |
97 | } | |
98 | } | |
99 | ||
7453a54e | 100 | pub fn expect_trait_item(self) -> ast::TraitItem { |
85aaf69f | 101 | match self { |
ff7c6d11 | 102 | Annotatable::TraitItem(i) => i.into_inner(), |
85aaf69f SL |
103 | _ => panic!("expected Item") |
104 | } | |
105 | } | |
106 | ||
7453a54e | 107 | pub fn expect_impl_item(self) -> ast::ImplItem { |
85aaf69f | 108 | match self { |
ff7c6d11 | 109 | Annotatable::ImplItem(i) => i.into_inner(), |
85aaf69f SL |
110 | _ => panic!("expected Item") |
111 | } | |
112 | } | |
ff7c6d11 | 113 | |
83c7162d XL |
114 | pub fn expect_foreign_item(self) -> ast::ForeignItem { |
115 | match self { | |
116 | Annotatable::ForeignItem(i) => i.into_inner(), | |
117 | _ => panic!("expected foreign item") | |
118 | } | |
119 | } | |
120 | ||
0531ce1d XL |
121 | pub fn expect_stmt(self) -> ast::Stmt { |
122 | match self { | |
123 | Annotatable::Stmt(stmt) => stmt.into_inner(), | |
124 | _ => panic!("expected statement"), | |
125 | } | |
126 | } | |
127 | ||
128 | pub fn expect_expr(self) -> P<ast::Expr> { | |
129 | match self { | |
130 | Annotatable::Expr(expr) => expr, | |
131 | _ => panic!("expected expression"), | |
132 | } | |
133 | } | |
134 | ||
ff7c6d11 XL |
135 | pub fn derive_allowed(&self) -> bool { |
136 | match *self { | |
137 | Annotatable::Item(ref item) => match item.node { | |
138 | ast::ItemKind::Struct(..) | | |
139 | ast::ItemKind::Enum(..) | | |
140 | ast::ItemKind::Union(..) => true, | |
141 | _ => false, | |
142 | }, | |
143 | _ => false, | |
144 | } | |
145 | } | |
85aaf69f SL |
146 | } |
147 | ||
d9579d0f AL |
148 | // A more flexible ItemDecorator. |
149 | pub trait MultiItemDecorator { | |
150 | fn expand(&self, | |
151 | ecx: &mut ExtCtxt, | |
152 | sp: Span, | |
153 | meta_item: &ast::MetaItem, | |
62682a34 | 154 | item: &Annotatable, |
d9579d0f AL |
155 | push: &mut FnMut(Annotatable)); |
156 | } | |
157 | ||
158 | impl<F> MultiItemDecorator for F | |
62682a34 | 159 | where F : Fn(&mut ExtCtxt, Span, &ast::MetaItem, &Annotatable, &mut FnMut(Annotatable)) |
d9579d0f AL |
160 | { |
161 | fn expand(&self, | |
162 | ecx: &mut ExtCtxt, | |
163 | sp: Span, | |
164 | meta_item: &ast::MetaItem, | |
62682a34 | 165 | item: &Annotatable, |
d9579d0f AL |
166 | push: &mut FnMut(Annotatable)) { |
167 | (*self)(ecx, sp, meta_item, item, push) | |
168 | } | |
169 | } | |
170 | ||
3157f602 | 171 | // `meta_item` is the annotation, and `item` is the item being modified. |
85aaf69f SL |
172 | // FIXME Decorators should follow the same pattern too. |
173 | pub trait MultiItemModifier { | |
174 | fn expand(&self, | |
175 | ecx: &mut ExtCtxt, | |
176 | span: Span, | |
177 | meta_item: &ast::MetaItem, | |
178 | item: Annotatable) | |
3157f602 | 179 | -> Vec<Annotatable>; |
85aaf69f SL |
180 | } |
181 | ||
3157f602 XL |
182 | impl<F, T> MultiItemModifier for F |
183 | where F: Fn(&mut ExtCtxt, Span, &ast::MetaItem, Annotatable) -> T, | |
184 | T: Into<Vec<Annotatable>>, | |
85aaf69f SL |
185 | { |
186 | fn expand(&self, | |
187 | ecx: &mut ExtCtxt, | |
188 | span: Span, | |
189 | meta_item: &ast::MetaItem, | |
190 | item: Annotatable) | |
3157f602 XL |
191 | -> Vec<Annotatable> { |
192 | (*self)(ecx, span, meta_item, item).into() | |
193 | } | |
194 | } | |
195 | ||
196 | impl Into<Vec<Annotatable>> for Annotatable { | |
197 | fn into(self) -> Vec<Annotatable> { | |
198 | vec![self] | |
85aaf69f SL |
199 | } |
200 | } | |
201 | ||
9e0c209e SL |
202 | pub trait ProcMacro { |
203 | fn expand<'cx>(&self, | |
204 | ecx: &'cx mut ExtCtxt, | |
205 | span: Span, | |
206 | ts: TokenStream) | |
207 | -> TokenStream; | |
208 | } | |
209 | ||
210 | impl<F> ProcMacro for F | |
211 | where F: Fn(TokenStream) -> TokenStream | |
212 | { | |
213 | fn expand<'cx>(&self, | |
214 | _ecx: &'cx mut ExtCtxt, | |
215 | _span: Span, | |
216 | ts: TokenStream) | |
217 | -> TokenStream { | |
218 | // FIXME setup implicit context in TLS before calling self. | |
219 | (*self)(ts) | |
220 | } | |
221 | } | |
222 | ||
223 | pub trait AttrProcMacro { | |
224 | fn expand<'cx>(&self, | |
225 | ecx: &'cx mut ExtCtxt, | |
226 | span: Span, | |
227 | annotation: TokenStream, | |
228 | annotated: TokenStream) | |
229 | -> TokenStream; | |
230 | } | |
231 | ||
232 | impl<F> AttrProcMacro for F | |
233 | where F: Fn(TokenStream, TokenStream) -> TokenStream | |
234 | { | |
235 | fn expand<'cx>(&self, | |
236 | _ecx: &'cx mut ExtCtxt, | |
237 | _span: Span, | |
238 | annotation: TokenStream, | |
239 | annotated: TokenStream) | |
240 | -> TokenStream { | |
241 | // FIXME setup implicit context in TLS before calling self. | |
242 | (*self)(annotation, annotated) | |
243 | } | |
244 | } | |
245 | ||
1a4d82fc JJ |
246 | /// Represents a thing that maps token trees to Macro Results |
247 | pub trait TTMacroExpander { | |
8bb4bdeb | 248 | fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream) |
1a4d82fc | 249 | -> Box<MacResult+'cx>; |
223e47cc LB |
250 | } |
251 | ||
1a4d82fc | 252 | pub type MacroExpanderFn = |
3157f602 XL |
253 | for<'cx> fn(&'cx mut ExtCtxt, Span, &[tokenstream::TokenTree]) |
254 | -> Box<MacResult+'cx>; | |
223e47cc | 255 | |
1a4d82fc | 256 | impl<F> TTMacroExpander for F |
8bb4bdeb | 257 | where F: for<'cx> Fn(&'cx mut ExtCtxt, Span, &[tokenstream::TokenTree]) -> Box<MacResult+'cx> |
1a4d82fc | 258 | { |
8bb4bdeb | 259 | fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, span: Span, input: TokenStream) |
1a4d82fc | 260 | -> Box<MacResult+'cx> { |
cc61c64b XL |
261 | struct AvoidInterpolatedIdents; |
262 | ||
263 | impl Folder for AvoidInterpolatedIdents { | |
264 | fn fold_tt(&mut self, tt: tokenstream::TokenTree) -> tokenstream::TokenTree { | |
265 | if let tokenstream::TokenTree::Token(_, token::Interpolated(ref nt)) = tt { | |
0531ce1d XL |
266 | if let token::NtIdent(ident, is_raw) = nt.0 { |
267 | return tokenstream::TokenTree::Token(ident.span, | |
83c7162d | 268 | token::Ident(ident, is_raw)); |
cc61c64b XL |
269 | } |
270 | } | |
271 | fold::noop_fold_tt(tt, self) | |
272 | } | |
273 | ||
274 | fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { | |
275 | fold::noop_fold_mac(mac, self) | |
276 | } | |
277 | } | |
278 | ||
279 | let input: Vec<_> = | |
280 | input.trees().map(|tt| AvoidInterpolatedIdents.fold_tt(tt)).collect(); | |
281 | (*self)(ecx, span, &input) | |
1a4d82fc | 282 | } |
223e47cc LB |
283 | } |
284 | ||
1a4d82fc JJ |
285 | pub trait IdentMacroExpander { |
286 | fn expand<'cx>(&self, | |
287 | cx: &'cx mut ExtCtxt, | |
288 | sp: Span, | |
289 | ident: ast::Ident, | |
32a655c1 | 290 | token_tree: Vec<tokenstream::TokenTree>) |
1a4d82fc JJ |
291 | -> Box<MacResult+'cx>; |
292 | } | |
223e47cc | 293 | |
1a4d82fc | 294 | pub type IdentMacroExpanderFn = |
3157f602 XL |
295 | for<'cx> fn(&'cx mut ExtCtxt, Span, ast::Ident, Vec<tokenstream::TokenTree>) |
296 | -> Box<MacResult+'cx>; | |
1a4d82fc JJ |
297 | |
298 | impl<F> IdentMacroExpander for F | |
299 | where F : for<'cx> Fn(&'cx mut ExtCtxt, Span, ast::Ident, | |
3157f602 | 300 | Vec<tokenstream::TokenTree>) -> Box<MacResult+'cx> |
1a4d82fc JJ |
301 | { |
302 | fn expand<'cx>(&self, | |
303 | cx: &'cx mut ExtCtxt, | |
304 | sp: Span, | |
305 | ident: ast::Ident, | |
32a655c1 | 306 | token_tree: Vec<tokenstream::TokenTree>) |
1a4d82fc JJ |
307 | -> Box<MacResult+'cx> |
308 | { | |
309 | (*self)(cx, sp, ident, token_tree) | |
310 | } | |
223e47cc LB |
311 | } |
312 | ||
c34b1796 | 313 | // Use a macro because forwarding to a simple function has type system issues |
9346a6ac | 314 | macro_rules! make_stmts_default { |
c34b1796 | 315 | ($me:expr) => { |
3157f602 XL |
316 | $me.make_expr().map(|e| SmallVector::one(ast::Stmt { |
317 | id: ast::DUMMY_NODE_ID, | |
318 | span: e.span, | |
319 | node: ast::StmtKind::Expr(e), | |
320 | })) | |
c34b1796 AL |
321 | } |
322 | } | |
323 | ||
1a4d82fc | 324 | /// The result of a macro expansion. The return values of the various |
c34b1796 | 325 | /// methods are spliced into the AST at the callsite of the macro. |
1a4d82fc JJ |
326 | pub trait MacResult { |
327 | /// Create an expression. | |
328 | fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> { | |
329 | None | |
330 | } | |
331 | /// Create zero or more items. | |
332 | fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> { | |
333 | None | |
334 | } | |
223e47cc | 335 | |
c34b1796 | 336 | /// Create zero or more impl items. |
7453a54e | 337 | fn make_impl_items(self: Box<Self>) -> Option<SmallVector<ast::ImplItem>> { |
1a4d82fc JJ |
338 | None |
339 | } | |
223e47cc | 340 | |
3157f602 XL |
341 | /// Create zero or more trait items. |
342 | fn make_trait_items(self: Box<Self>) -> Option<SmallVector<ast::TraitItem>> { | |
343 | None | |
344 | } | |
345 | ||
83c7162d XL |
346 | /// Create zero or more items in an `extern {}` block |
347 | fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> { None } | |
348 | ||
1a4d82fc JJ |
349 | /// Create a pattern. |
350 | fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> { | |
351 | None | |
352 | } | |
223e47cc | 353 | |
9346a6ac | 354 | /// Create zero or more statements. |
1a4d82fc JJ |
355 | /// |
356 | /// By default this attempts to create an expression statement, | |
357 | /// returning None if that fails. | |
7453a54e | 358 | fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> { |
9346a6ac | 359 | make_stmts_default!(self) |
1a4d82fc | 360 | } |
e9174d1e SL |
361 | |
362 | fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> { | |
363 | None | |
364 | } | |
1a4d82fc | 365 | } |
223e47cc | 366 | |
c34b1796 AL |
367 | macro_rules! make_MacEager { |
368 | ( $( $fld:ident: $t:ty, )* ) => { | |
369 | /// `MacResult` implementation for the common case where you've already | |
370 | /// built each form of AST that you might return. | |
371 | #[derive(Default)] | |
372 | pub struct MacEager { | |
373 | $( | |
374 | pub $fld: Option<$t>, | |
375 | )* | |
376 | } | |
377 | ||
378 | impl MacEager { | |
379 | $( | |
380 | pub fn $fld(v: $t) -> Box<MacResult> { | |
d9579d0f | 381 | Box::new(MacEager { |
c34b1796 AL |
382 | $fld: Some(v), |
383 | ..Default::default() | |
d9579d0f | 384 | }) |
c34b1796 AL |
385 | } |
386 | )* | |
1a4d82fc JJ |
387 | } |
388 | } | |
389 | } | |
c34b1796 AL |
390 | |
391 | make_MacEager! { | |
392 | expr: P<ast::Expr>, | |
393 | pat: P<ast::Pat>, | |
394 | items: SmallVector<P<ast::Item>>, | |
7453a54e | 395 | impl_items: SmallVector<ast::ImplItem>, |
3157f602 | 396 | trait_items: SmallVector<ast::TraitItem>, |
83c7162d | 397 | foreign_items: SmallVector<ast::ForeignItem>, |
7453a54e | 398 | stmts: SmallVector<ast::Stmt>, |
e9174d1e | 399 | ty: P<ast::Ty>, |
1a4d82fc | 400 | } |
c34b1796 AL |
401 | |
402 | impl MacResult for MacEager { | |
403 | fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> { | |
404 | self.expr | |
1a4d82fc | 405 | } |
c34b1796 AL |
406 | |
407 | fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> { | |
408 | self.items | |
1a4d82fc | 409 | } |
223e47cc | 410 | |
7453a54e | 411 | fn make_impl_items(self: Box<Self>) -> Option<SmallVector<ast::ImplItem>> { |
c34b1796 | 412 | self.impl_items |
1a4d82fc | 413 | } |
223e47cc | 414 | |
3157f602 XL |
415 | fn make_trait_items(self: Box<Self>) -> Option<SmallVector<ast::TraitItem>> { |
416 | self.trait_items | |
417 | } | |
418 | ||
83c7162d XL |
419 | fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> { |
420 | self.foreign_items | |
421 | } | |
422 | ||
7453a54e | 423 | fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> { |
9346a6ac AL |
424 | match self.stmts.as_ref().map_or(0, |s| s.len()) { |
425 | 0 => make_stmts_default!(self), | |
426 | _ => self.stmts, | |
c34b1796 AL |
427 | } |
428 | } | |
429 | ||
430 | fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> { | |
431 | if let Some(p) = self.pat { | |
432 | return Some(p); | |
433 | } | |
434 | if let Some(e) = self.expr { | |
7453a54e | 435 | if let ast::ExprKind::Lit(_) = e.node { |
c34b1796 AL |
436 | return Some(P(ast::Pat { |
437 | id: ast::DUMMY_NODE_ID, | |
438 | span: e.span, | |
7453a54e | 439 | node: PatKind::Lit(e), |
c34b1796 AL |
440 | })); |
441 | } | |
442 | } | |
443 | None | |
1a4d82fc | 444 | } |
e9174d1e SL |
445 | |
446 | fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> { | |
447 | self.ty | |
448 | } | |
1a4d82fc | 449 | } |
223e47cc | 450 | |
1a4d82fc JJ |
451 | /// Fill-in macro expansion result, to allow compilation to continue |
452 | /// after hitting errors. | |
c34b1796 | 453 | #[derive(Copy, Clone)] |
1a4d82fc JJ |
454 | pub struct DummyResult { |
455 | expr_only: bool, | |
456 | span: Span | |
223e47cc LB |
457 | } |
458 | ||
1a4d82fc JJ |
459 | impl DummyResult { |
460 | /// Create a default MacResult that can be anything. | |
461 | /// | |
462 | /// Use this as a return value after hitting any errors and | |
463 | /// calling `span_err`. | |
464 | pub fn any(sp: Span) -> Box<MacResult+'static> { | |
d9579d0f | 465 | Box::new(DummyResult { expr_only: false, span: sp }) |
1a4d82fc JJ |
466 | } |
467 | ||
468 | /// Create a default MacResult that can only be an expression. | |
469 | /// | |
470 | /// Use this for macros that must expand to an expression, so even | |
471 | /// if an error is encountered internally, the user will receive | |
472 | /// an error that they also used it in the wrong place. | |
473 | pub fn expr(sp: Span) -> Box<MacResult+'static> { | |
d9579d0f | 474 | Box::new(DummyResult { expr_only: true, span: sp }) |
1a4d82fc JJ |
475 | } |
476 | ||
477 | /// A plain dummy expression. | |
478 | pub fn raw_expr(sp: Span) -> P<ast::Expr> { | |
479 | P(ast::Expr { | |
480 | id: ast::DUMMY_NODE_ID, | |
7453a54e | 481 | node: ast::ExprKind::Lit(P(codemap::respan(sp, ast::LitKind::Bool(false)))), |
1a4d82fc | 482 | span: sp, |
3157f602 | 483 | attrs: ast::ThinVec::new(), |
1a4d82fc JJ |
484 | }) |
485 | } | |
486 | ||
487 | /// A plain dummy pattern. | |
488 | pub fn raw_pat(sp: Span) -> ast::Pat { | |
489 | ast::Pat { | |
490 | id: ast::DUMMY_NODE_ID, | |
7453a54e | 491 | node: PatKind::Wild, |
1a4d82fc JJ |
492 | span: sp, |
493 | } | |
494 | } | |
495 | ||
e9174d1e SL |
496 | pub fn raw_ty(sp: Span) -> P<ast::Ty> { |
497 | P(ast::Ty { | |
498 | id: ast::DUMMY_NODE_ID, | |
7453a54e | 499 | node: ast::TyKind::Infer, |
e9174d1e SL |
500 | span: sp |
501 | }) | |
502 | } | |
1a4d82fc JJ |
503 | } |
504 | ||
505 | impl MacResult for DummyResult { | |
506 | fn make_expr(self: Box<DummyResult>) -> Option<P<ast::Expr>> { | |
507 | Some(DummyResult::raw_expr(self.span)) | |
508 | } | |
e9174d1e | 509 | |
1a4d82fc JJ |
510 | fn make_pat(self: Box<DummyResult>) -> Option<P<ast::Pat>> { |
511 | Some(P(DummyResult::raw_pat(self.span))) | |
512 | } | |
e9174d1e | 513 | |
1a4d82fc JJ |
514 | fn make_items(self: Box<DummyResult>) -> Option<SmallVector<P<ast::Item>>> { |
515 | // this code needs a comment... why not always just return the Some() ? | |
516 | if self.expr_only { | |
517 | None | |
518 | } else { | |
476ff2be | 519 | Some(SmallVector::new()) |
1a4d82fc JJ |
520 | } |
521 | } | |
e9174d1e | 522 | |
7453a54e | 523 | fn make_impl_items(self: Box<DummyResult>) -> Option<SmallVector<ast::ImplItem>> { |
1a4d82fc JJ |
524 | if self.expr_only { |
525 | None | |
526 | } else { | |
476ff2be | 527 | Some(SmallVector::new()) |
1a4d82fc JJ |
528 | } |
529 | } | |
e9174d1e | 530 | |
3157f602 XL |
531 | fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVector<ast::TraitItem>> { |
532 | if self.expr_only { | |
533 | None | |
534 | } else { | |
476ff2be | 535 | Some(SmallVector::new()) |
3157f602 XL |
536 | } |
537 | } | |
538 | ||
83c7162d XL |
539 | fn make_foreign_items(self: Box<Self>) -> Option<SmallVector<ast::ForeignItem>> { |
540 | if self.expr_only { | |
541 | None | |
542 | } else { | |
543 | Some(SmallVector::new()) | |
544 | } | |
545 | } | |
546 | ||
7453a54e | 547 | fn make_stmts(self: Box<DummyResult>) -> Option<SmallVector<ast::Stmt>> { |
3157f602 XL |
548 | Some(SmallVector::one(ast::Stmt { |
549 | id: ast::DUMMY_NODE_ID, | |
550 | node: ast::StmtKind::Expr(DummyResult::raw_expr(self.span)), | |
551 | span: self.span, | |
552 | })) | |
553 | } | |
554 | ||
555 | fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> { | |
556 | Some(DummyResult::raw_ty(self.span)) | |
1a4d82fc JJ |
557 | } |
558 | } | |
559 | ||
8bb4bdeb XL |
560 | pub type BuiltinDeriveFn = |
561 | for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable)); | |
562 | ||
563 | /// Represents different kinds of macro invocations that can be resolved. | |
564 | #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] | |
565 | pub enum MacroKind { | |
566 | /// A bang macro - foo!() | |
567 | Bang, | |
568 | /// An attribute macro - #[foo] | |
569 | Attr, | |
570 | /// A derive attribute macro - #[derive(Foo)] | |
571 | Derive, | |
572 | } | |
573 | ||
1a4d82fc JJ |
574 | /// An enum representing the different kinds of syntax extensions. |
575 | pub enum SyntaxExtension { | |
d9579d0f AL |
576 | /// A syntax extension that is attached to an item and creates new items |
577 | /// based upon it. | |
578 | /// | |
579 | /// `#[derive(...)]` is a `MultiItemDecorator`. | |
9e0c209e SL |
580 | /// |
581 | /// Prefer ProcMacro or MultiModifier since they are more flexible. | |
83c7162d | 582 | MultiDecorator(Box<MultiItemDecorator + sync::Sync + sync::Send>), |
d9579d0f | 583 | |
85aaf69f | 584 | /// A syntax extension that is attached to an item and modifies it |
9e0c209e | 585 | /// in-place. Also allows decoration, i.e., creating new items. |
83c7162d | 586 | MultiModifier(Box<MultiItemModifier + sync::Sync + sync::Send>), |
9e0c209e SL |
587 | |
588 | /// A function-like procedural macro. TokenStream -> TokenStream. | |
83c7162d | 589 | ProcMacro(Box<ProcMacro + sync::Sync + sync::Send>), |
9e0c209e SL |
590 | |
591 | /// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream. | |
592 | /// The first TokenSteam is the attribute, the second is the annotated item. | |
593 | /// Allows modification of the input items and adding new items, similar to | |
594 | /// MultiModifier, but uses TokenStreams, rather than AST nodes. | |
83c7162d | 595 | AttrProcMacro(Box<AttrProcMacro + sync::Sync + sync::Send>), |
85aaf69f | 596 | |
1a4d82fc JJ |
597 | /// A normal, function-like syntax extension. |
598 | /// | |
599 | /// `bytes!` is a `NormalTT`. | |
3b2f2976 | 600 | NormalTT { |
83c7162d | 601 | expander: Box<TTMacroExpander + sync::Sync + sync::Send>, |
3b2f2976 XL |
602 | def_info: Option<(ast::NodeId, Span)>, |
603 | /// Whether the contents of the macro can | |
604 | /// directly use `#[unstable]` things (true == yes). | |
605 | allow_internal_unstable: bool, | |
606 | /// Whether the contents of the macro can use `unsafe` | |
607 | /// without triggering the `unsafe_code` lint. | |
608 | allow_internal_unsafe: bool, | |
0531ce1d XL |
609 | /// The macro's feature name if it is unstable, and the stability feature |
610 | unstable_feature: Option<(Symbol, u32)>, | |
3b2f2976 | 611 | }, |
1a4d82fc JJ |
612 | |
613 | /// A function-like syntax extension that has an extra ident before | |
614 | /// the block. | |
615 | /// | |
83c7162d | 616 | IdentTT(Box<IdentMacroExpander + sync::Sync + sync::Send>, Option<Span>, bool), |
c30ab7b3 | 617 | |
8bb4bdeb XL |
618 | /// An attribute-like procedural macro. TokenStream -> TokenStream. |
619 | /// The input is the annotated item. | |
620 | /// Allows generating code to implement a Trait for a given struct | |
621 | /// or enum item. | |
83c7162d XL |
622 | ProcMacroDerive(Box<MultiItemModifier + |
623 | sync::Sync + | |
624 | sync::Send>, Vec<Symbol> /* inert attribute names */), | |
8bb4bdeb XL |
625 | |
626 | /// An attribute-like procedural macro that derives a builtin trait. | |
627 | BuiltinDerive(BuiltinDeriveFn), | |
7cac9316 XL |
628 | |
629 | /// A declarative macro, e.g. `macro m() {}`. | |
630 | /// | |
631 | /// The second element is the definition site span. | |
83c7162d | 632 | DeclMacro(Box<TTMacroExpander + sync::Sync + sync::Send>, Option<(ast::NodeId, Span)>), |
8bb4bdeb XL |
633 | } |
634 | ||
635 | impl SyntaxExtension { | |
636 | /// Return which kind of macro calls this syntax extension. | |
637 | pub fn kind(&self) -> MacroKind { | |
638 | match *self { | |
7cac9316 | 639 | SyntaxExtension::DeclMacro(..) | |
3b2f2976 | 640 | SyntaxExtension::NormalTT { .. } | |
8bb4bdeb XL |
641 | SyntaxExtension::IdentTT(..) | |
642 | SyntaxExtension::ProcMacro(..) => | |
643 | MacroKind::Bang, | |
644 | SyntaxExtension::MultiDecorator(..) | | |
645 | SyntaxExtension::MultiModifier(..) | | |
646 | SyntaxExtension::AttrProcMacro(..) => | |
647 | MacroKind::Attr, | |
648 | SyntaxExtension::ProcMacroDerive(..) | | |
649 | SyntaxExtension::BuiltinDerive(..) => | |
650 | MacroKind::Derive, | |
651 | } | |
652 | } | |
7cac9316 XL |
653 | |
654 | pub fn is_modern(&self) -> bool { | |
655 | match *self { | |
041b39d2 XL |
656 | SyntaxExtension::DeclMacro(..) | |
657 | SyntaxExtension::ProcMacro(..) | | |
658 | SyntaxExtension::AttrProcMacro(..) | | |
659 | SyntaxExtension::ProcMacroDerive(..) => true, | |
7cac9316 XL |
660 | _ => false, |
661 | } | |
662 | } | |
1a4d82fc JJ |
663 | } |
664 | ||
665 | pub type NamedSyntaxExtension = (Name, SyntaxExtension); | |
666 | ||
9e0c209e SL |
667 | pub trait Resolver { |
668 | fn next_node_id(&mut self) -> ast::NodeId; | |
c30ab7b3 | 669 | fn get_module_scope(&mut self, id: ast::NodeId) -> Mark; |
476ff2be | 670 | fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item>; |
32a655c1 | 671 | fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool; |
9e0c209e | 672 | |
8bb4bdeb | 673 | fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion, derives: &[Mark]); |
0531ce1d | 674 | fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc<SyntaxExtension>); |
9e0c209e | 675 | |
476ff2be | 676 | fn resolve_imports(&mut self); |
8bb4bdeb | 677 | // Resolves attribute and derive legacy macros from `#![plugin(..)]`. |
0531ce1d XL |
678 | fn find_legacy_attr_invoc(&mut self, attrs: &mut Vec<Attribute>, allow_derive: bool) |
679 | -> Option<Attribute>; | |
680 | ||
8bb4bdeb | 681 | fn resolve_invoc(&mut self, invoc: &mut Invocation, scope: Mark, force: bool) |
0531ce1d | 682 | -> Result<Option<Lrc<SyntaxExtension>>, Determinacy>; |
8bb4bdeb | 683 | fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) |
0531ce1d | 684 | -> Result<Lrc<SyntaxExtension>, Determinacy>; |
7cac9316 | 685 | fn check_unused_macros(&self); |
c30ab7b3 SL |
686 | } |
687 | ||
3b2f2976 | 688 | #[derive(Copy, Clone, Debug, PartialEq)] |
c30ab7b3 SL |
689 | pub enum Determinacy { |
690 | Determined, | |
691 | Undetermined, | |
970d7e83 LB |
692 | } |
693 | ||
9e0c209e SL |
694 | pub struct DummyResolver; |
695 | ||
696 | impl Resolver for DummyResolver { | |
697 | fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID } | |
c30ab7b3 | 698 | fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() } |
476ff2be | 699 | fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item } |
32a655c1 | 700 | fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false } |
9e0c209e | 701 | |
8bb4bdeb | 702 | fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion, _derives: &[Mark]) {} |
0531ce1d | 703 | fn add_builtin(&mut self, _ident: ast::Ident, _ext: Lrc<SyntaxExtension>) {} |
9e0c209e | 704 | |
476ff2be | 705 | fn resolve_imports(&mut self) {} |
0531ce1d XL |
706 | fn find_legacy_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>, _allow_derive: bool) |
707 | -> Option<Attribute> { None } | |
8bb4bdeb | 708 | fn resolve_invoc(&mut self, _invoc: &mut Invocation, _scope: Mark, _force: bool) |
0531ce1d | 709 | -> Result<Option<Lrc<SyntaxExtension>>, Determinacy> { |
8bb4bdeb XL |
710 | Err(Determinacy::Determined) |
711 | } | |
712 | fn resolve_macro(&mut self, _scope: Mark, _path: &ast::Path, _kind: MacroKind, | |
0531ce1d | 713 | _force: bool) -> Result<Lrc<SyntaxExtension>, Determinacy> { |
c30ab7b3 | 714 | Err(Determinacy::Determined) |
1a4d82fc | 715 | } |
7cac9316 | 716 | fn check_unused_macros(&self) {} |
1a4d82fc | 717 | } |
970d7e83 | 718 | |
9e0c209e SL |
719 | #[derive(Clone)] |
720 | pub struct ModuleData { | |
721 | pub mod_path: Vec<ast::Ident>, | |
722 | pub directory: PathBuf, | |
723 | } | |
724 | ||
725 | #[derive(Clone)] | |
726 | pub struct ExpansionData { | |
727 | pub mark: Mark, | |
728 | pub depth: usize, | |
9e0c209e | 729 | pub module: Rc<ModuleData>, |
476ff2be | 730 | pub directory_ownership: DirectoryOwnership, |
0531ce1d | 731 | pub crate_span: Option<Span>, |
3157f602 XL |
732 | } |
733 | ||
1a4d82fc | 734 | /// One of these is made during expansion and incrementally updated as we go; |
7cac9316 XL |
735 | /// when a macro expansion occurs, the resulting nodes have the `backtrace() |
736 | /// -> expn_info` of their expansion context stored into their span. | |
1a4d82fc JJ |
737 | pub struct ExtCtxt<'a> { |
738 | pub parse_sess: &'a parse::ParseSess, | |
85aaf69f | 739 | pub ecfg: expand::ExpansionConfig<'a>, |
ff7c6d11 | 740 | pub root_path: PathBuf, |
9e0c209e | 741 | pub resolver: &'a mut Resolver, |
c30ab7b3 | 742 | pub resolve_err_count: usize, |
9e0c209e | 743 | pub current_expansion: ExpansionData, |
7cac9316 | 744 | pub expansions: HashMap<Span, Vec<String>>, |
1a4d82fc JJ |
745 | } |
746 | ||
747 | impl<'a> ExtCtxt<'a> { | |
c30ab7b3 | 748 | pub fn new(parse_sess: &'a parse::ParseSess, |
e9174d1e | 749 | ecfg: expand::ExpansionConfig<'a>, |
9e0c209e | 750 | resolver: &'a mut Resolver) |
3157f602 | 751 | -> ExtCtxt<'a> { |
1a4d82fc | 752 | ExtCtxt { |
3b2f2976 XL |
753 | parse_sess, |
754 | ecfg, | |
ff7c6d11 | 755 | root_path: PathBuf::new(), |
3b2f2976 | 756 | resolver, |
c30ab7b3 | 757 | resolve_err_count: 0, |
9e0c209e SL |
758 | current_expansion: ExpansionData { |
759 | mark: Mark::root(), | |
760 | depth: 0, | |
9e0c209e | 761 | module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), |
ff7c6d11 | 762 | directory_ownership: DirectoryOwnership::Owned { relative: None }, |
0531ce1d | 763 | crate_span: None, |
9e0c209e | 764 | }, |
7cac9316 | 765 | expansions: HashMap::new(), |
970d7e83 LB |
766 | } |
767 | } | |
768 | ||
b039eaaf | 769 | /// Returns a `Folder` for deeply expanding all macros in an AST node. |
1a4d82fc | 770 | pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { |
9e0c209e SL |
771 | expand::MacroExpander::new(self, false) |
772 | } | |
773 | ||
774 | /// Returns a `Folder` that deeply expands all macros and assigns all node ids in an AST node. | |
775 | /// Once node ids are assigned, the node may not be expanded, removed, or otherwise modified. | |
776 | pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { | |
777 | expand::MacroExpander::new(self, true) | |
1a4d82fc JJ |
778 | } |
779 | ||
8bb4bdeb XL |
780 | pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) -> parser::Parser<'a> { |
781 | parse::stream_to_parser(self.parse_sess, tts.iter().cloned().collect()) | |
1a4d82fc | 782 | } |
62682a34 | 783 | pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() } |
1a4d82fc | 784 | pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } |
c30ab7b3 | 785 | pub fn cfg(&self) -> &ast::CrateConfig { &self.parse_sess.config } |
1a4d82fc | 786 | pub fn call_site(&self) -> Span { |
cc61c64b | 787 | match self.current_expansion.mark.expn_info() { |
1a4d82fc | 788 | Some(expn_info) => expn_info.call_site, |
cc61c64b XL |
789 | None => DUMMY_SP, |
790 | } | |
791 | } | |
792 | pub fn backtrace(&self) -> SyntaxContext { | |
793 | SyntaxContext::empty().apply_mark(self.current_expansion.mark) | |
970d7e83 | 794 | } |
d9579d0f | 795 | |
d9579d0f AL |
796 | /// Returns span for the macro which originally caused the current expansion to happen. |
797 | /// | |
798 | /// Stops backtracing at include! boundary. | |
cc61c64b XL |
799 | pub fn expansion_cause(&self) -> Option<Span> { |
800 | let mut ctxt = self.backtrace(); | |
d9579d0f | 801 | let mut last_macro = None; |
1a4d82fc | 802 | loop { |
cc61c64b XL |
803 | if ctxt.outer().expn_info().map_or(None, |info| { |
804 | if info.callee.name() == "include" { | |
805 | // Stop going up the backtrace once include! is encountered | |
806 | return None; | |
807 | } | |
ea8adc8c | 808 | ctxt = info.call_site.ctxt(); |
cc61c64b | 809 | last_macro = Some(info.call_site); |
7cac9316 | 810 | Some(()) |
d9579d0f AL |
811 | }).is_none() { |
812 | break | |
223e47cc | 813 | } |
1a4d82fc | 814 | } |
cc61c64b | 815 | last_macro |
1a4d82fc | 816 | } |
1a4d82fc | 817 | |
2c00a5a8 XL |
818 | pub fn struct_span_warn<S: Into<MultiSpan>>(&self, |
819 | sp: S, | |
820 | msg: &str) | |
821 | -> DiagnosticBuilder<'a> { | |
9cc50fc6 SL |
822 | self.parse_sess.span_diagnostic.struct_span_warn(sp, msg) |
823 | } | |
2c00a5a8 XL |
824 | pub fn struct_span_err<S: Into<MultiSpan>>(&self, |
825 | sp: S, | |
826 | msg: &str) | |
827 | -> DiagnosticBuilder<'a> { | |
9cc50fc6 SL |
828 | self.parse_sess.span_diagnostic.struct_span_err(sp, msg) |
829 | } | |
2c00a5a8 XL |
830 | pub fn struct_span_fatal<S: Into<MultiSpan>>(&self, |
831 | sp: S, | |
832 | msg: &str) | |
833 | -> DiagnosticBuilder<'a> { | |
9cc50fc6 SL |
834 | self.parse_sess.span_diagnostic.struct_span_fatal(sp, msg) |
835 | } | |
836 | ||
1a4d82fc JJ |
837 | /// Emit `msg` attached to `sp`, and stop compilation immediately. |
838 | /// | |
839 | /// `span_err` should be strongly preferred where-ever possible: | |
ff7c6d11 XL |
840 | /// this should *only* be used when: |
841 | /// | |
1a4d82fc JJ |
842 | /// - continuing has a high risk of flow-on errors (e.g. errors in |
843 | /// declaring a macro would cause all uses of that macro to | |
844 | /// complain about "undefined macro"), or | |
845 | /// - there is literally nothing else that can be done (however, | |
846 | /// in most cases one can construct a dummy expression/item to | |
847 | /// substitute; we never hit resolve/type-checking so the dummy | |
848 | /// value doesn't have to match anything) | |
2c00a5a8 XL |
849 | pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { |
850 | self.parse_sess.span_diagnostic.span_fatal(sp, msg).raise(); | |
970d7e83 | 851 | } |
1a4d82fc JJ |
852 | |
853 | /// Emit `msg` attached to `sp`, without immediately stopping | |
854 | /// compilation. | |
855 | /// | |
856 | /// Compilation will be stopped in the near future (at the end of | |
857 | /// the macro expansion phase). | |
2c00a5a8 | 858 | pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
970d7e83 LB |
859 | self.parse_sess.span_diagnostic.span_err(sp, msg); |
860 | } | |
83c7162d XL |
861 | pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: DiagnosticId) { |
862 | self.parse_sess.span_diagnostic.span_err_with_code(sp, msg, code); | |
863 | } | |
2c00a5a8 | 864 | pub fn mut_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) |
ea8adc8c XL |
865 | -> DiagnosticBuilder<'a> { |
866 | self.parse_sess.span_diagnostic.mut_span_err(sp, msg) | |
867 | } | |
2c00a5a8 | 868 | pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { |
970d7e83 LB |
869 | self.parse_sess.span_diagnostic.span_warn(sp, msg); |
870 | } | |
2c00a5a8 | 871 | pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { |
970d7e83 LB |
872 | self.parse_sess.span_diagnostic.span_unimpl(sp, msg); |
873 | } | |
2c00a5a8 | 874 | pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { |
970d7e83 LB |
875 | self.parse_sess.span_diagnostic.span_bug(sp, msg); |
876 | } | |
ea8adc8c | 877 | pub fn trace_macros_diag(&mut self) { |
7cac9316 XL |
878 | for (sp, notes) in self.expansions.iter() { |
879 | let mut db = self.parse_sess.span_diagnostic.span_note_diag(*sp, "trace_macro"); | |
880 | for note in notes { | |
881 | db.note(note); | |
882 | } | |
883 | db.emit(); | |
884 | } | |
ea8adc8c XL |
885 | // Fixme: does this result in errors? |
886 | self.expansions.clear(); | |
7cac9316 | 887 | } |
970d7e83 | 888 | pub fn bug(&self, msg: &str) -> ! { |
9cc50fc6 | 889 | self.parse_sess.span_diagnostic.bug(msg); |
970d7e83 | 890 | } |
970d7e83 | 891 | pub fn trace_macros(&self) -> bool { |
d9579d0f | 892 | self.ecfg.trace_mac |
970d7e83 | 893 | } |
1a4d82fc | 894 | pub fn set_trace_macros(&mut self, x: bool) { |
d9579d0f | 895 | self.ecfg.trace_mac = x |
970d7e83 | 896 | } |
1a4d82fc | 897 | pub fn ident_of(&self, st: &str) -> ast::Ident { |
476ff2be | 898 | ast::Ident::from_str(st) |
970d7e83 | 899 | } |
e9174d1e | 900 | pub fn std_path(&self, components: &[&str]) -> Vec<ast::Ident> { |
83c7162d XL |
901 | let def_site = DUMMY_SP.apply_mark(self.current_expansion.mark); |
902 | iter::once(Ident::new(keywords::DollarCrate.name(), def_site)) | |
ff7c6d11 XL |
903 | .chain(components.iter().map(|s| self.ident_of(s))) |
904 | .collect() | |
85aaf69f | 905 | } |
1a4d82fc | 906 | pub fn name_of(&self, st: &str) -> ast::Name { |
476ff2be | 907 | Symbol::intern(st) |
223e47cc | 908 | } |
7cac9316 XL |
909 | |
910 | pub fn check_unused_macros(&self) { | |
911 | self.resolver.check_unused_macros(); | |
912 | } | |
223e47cc LB |
913 | } |
914 | ||
1a4d82fc JJ |
915 | /// Extract a string literal from the macro expanded version of `expr`, |
916 | /// emitting `err_msg` if `expr` is not a string literal. This does not stop | |
917 | /// compilation on error, merely emits a non-fatal error and returns None. | |
9e0c209e | 918 | pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P<ast::Expr>, err_msg: &str) |
476ff2be | 919 | -> Option<Spanned<(Symbol, ast::StrStyle)>> { |
cc61c64b | 920 | // Update `expr.span`'s ctxt now in case expr is an `include!` macro invocation. |
3157f602 | 921 | let expr = expr.map(|mut expr| { |
83c7162d | 922 | expr.span = expr.span.apply_mark(cx.current_expansion.mark); |
3157f602 XL |
923 | expr |
924 | }); | |
925 | ||
1a4d82fc JJ |
926 | // we want to be able to handle e.g. concat("foo", "bar") |
927 | let expr = cx.expander().fold_expr(expr); | |
223e47cc | 928 | match expr.node { |
7453a54e | 929 | ast::ExprKind::Lit(ref l) => match l.node { |
476ff2be | 930 | ast::LitKind::Str(s, style) => return Some(respan(expr.span, (s, style))), |
1a4d82fc JJ |
931 | _ => cx.span_err(l.span, err_msg) |
932 | }, | |
933 | _ => cx.span_err(expr.span, err_msg) | |
223e47cc | 934 | } |
1a4d82fc | 935 | None |
223e47cc LB |
936 | } |
937 | ||
9e0c209e | 938 | pub fn expr_to_string(cx: &mut ExtCtxt, expr: P<ast::Expr>, err_msg: &str) |
476ff2be | 939 | -> Option<(Symbol, ast::StrStyle)> { |
9e0c209e SL |
940 | expr_to_spanned_string(cx, expr, err_msg).map(|s| s.node) |
941 | } | |
942 | ||
1a4d82fc JJ |
943 | /// Non-fatally assert that `tts` is empty. Note that this function |
944 | /// returns even when `tts` is non-empty, macros that *need* to stop | |
945 | /// compilation should call | |
946 | /// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be | |
947 | /// done as rarely as possible). | |
948 | pub fn check_zero_tts(cx: &ExtCtxt, | |
949 | sp: Span, | |
3157f602 | 950 | tts: &[tokenstream::TokenTree], |
223e47cc | 951 | name: &str) { |
9346a6ac | 952 | if !tts.is_empty() { |
c34b1796 | 953 | cx.span_err(sp, &format!("{} takes no arguments", name)); |
223e47cc LB |
954 | } |
955 | } | |
956 | ||
0531ce1d XL |
957 | /// Interpreting `tts` as a comma-separated sequence of expressions, |
958 | /// expect exactly one string literal, or emit an error and return None. | |
1a4d82fc JJ |
959 | pub fn get_single_str_from_tts(cx: &mut ExtCtxt, |
960 | sp: Span, | |
3157f602 | 961 | tts: &[tokenstream::TokenTree], |
1a4d82fc JJ |
962 | name: &str) |
963 | -> Option<String> { | |
964 | let mut p = cx.new_parser_from_tts(tts); | |
965 | if p.token == token::Eof { | |
c34b1796 | 966 | cx.span_err(sp, &format!("{} takes 1 argument", name)); |
1a4d82fc JJ |
967 | return None |
968 | } | |
9e0c209e | 969 | let ret = panictry!(p.parse_expr()); |
0531ce1d XL |
970 | let _ = p.eat(&token::Comma); |
971 | ||
1a4d82fc | 972 | if p.token != token::Eof { |
c34b1796 | 973 | cx.span_err(sp, &format!("{} takes 1 argument", name)); |
1a4d82fc JJ |
974 | } |
975 | expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| { | |
85aaf69f | 976 | s.to_string() |
1a4d82fc | 977 | }) |
223e47cc LB |
978 | } |
979 | ||
1a4d82fc JJ |
980 | /// Extract comma-separated expressions from `tts`. If there is a |
981 | /// parsing error, emit a non-fatal error and return None. | |
982 | pub fn get_exprs_from_tts(cx: &mut ExtCtxt, | |
983 | sp: Span, | |
3157f602 | 984 | tts: &[tokenstream::TokenTree]) -> Option<Vec<P<ast::Expr>>> { |
1a4d82fc JJ |
985 | let mut p = cx.new_parser_from_tts(tts); |
986 | let mut es = Vec::new(); | |
987 | while p.token != token::Eof { | |
92a42be0 | 988 | es.push(cx.expander().fold_expr(panictry!(p.parse_expr()))); |
9cc50fc6 | 989 | if p.eat(&token::Comma) { |
1a4d82fc JJ |
990 | continue; |
991 | } | |
992 | if p.token != token::Eof { | |
993 | cx.span_err(sp, "expected token: `,`"); | |
994 | return None; | |
223e47cc | 995 | } |
223e47cc | 996 | } |
1a4d82fc | 997 | Some(es) |
223e47cc | 998 | } |