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