]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/ext/base.rs
New upstream version 1.27.1+dfsg1
[rustc.git] / src / libsyntax / ext / base.rs
CommitLineData
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 11pub use self::SyntaxExtension::*;
1a4d82fc 12
8bb4bdeb 13use ast::{self, Attribute, Name, PatKind, MetaItem};
3157f602 14use attr::HasAttrs;
cc61c64b 15use codemap::{self, CodeMap, Spanned, respan};
2c00a5a8 16use syntax_pos::{Span, MultiSpan, DUMMY_SP};
83c7162d 17use errors::{DiagnosticBuilder, DiagnosticId};
8bb4bdeb 18use ext::expand::{self, Expansion, Invocation};
cc61c64b 19use ext::hygiene::{Mark, SyntaxContext};
9e0c209e 20use fold::{self, Folder};
476ff2be 21use parse::{self, parser, DirectoryOwnership};
223e47cc 22use parse::token;
1a4d82fc 23use ptr::P;
ff7c6d11 24use symbol::{keywords, Ident, Symbol};
1a4d82fc 25use util::small_vector::SmallVector;
1a4d82fc 26
7cac9316 27use std::collections::HashMap;
ff7c6d11 28use std::iter;
9e0c209e 29use std::path::PathBuf;
1a4d82fc 30use std::rc::Rc;
83c7162d 31use rustc_data_structures::sync::{self, Lrc};
c34b1796 32use std::default::Default;
9e0c209e 33use tokenstream::{self, TokenStream};
1a4d82fc 34
223e47cc 35
85aaf69f
SL
36#[derive(Debug,Clone)]
37pub 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 46impl 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
71impl 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.
149pub 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
158impl<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.
173pub 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
182impl<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
196impl Into<Vec<Annotatable>> for Annotatable {
197 fn into(self) -> Vec<Annotatable> {
198 vec![self]
85aaf69f
SL
199 }
200}
201
9e0c209e
SL
202pub trait ProcMacro {
203 fn expand<'cx>(&self,
204 ecx: &'cx mut ExtCtxt,
205 span: Span,
206 ts: TokenStream)
207 -> TokenStream;
208}
209
210impl<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
223pub 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
232impl<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
247pub 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 252pub type MacroExpanderFn =
3157f602
XL
253 for<'cx> fn(&'cx mut ExtCtxt, Span, &[tokenstream::TokenTree])
254 -> Box<MacResult+'cx>;
223e47cc 255
1a4d82fc 256impl<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
285pub 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 294pub type IdentMacroExpanderFn =
3157f602
XL
295 for<'cx> fn(&'cx mut ExtCtxt, Span, ast::Ident, Vec<tokenstream::TokenTree>)
296 -> Box<MacResult+'cx>;
1a4d82fc
JJ
297
298impl<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 314macro_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
326pub 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
367macro_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
391make_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
402impl 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
454pub struct DummyResult {
455 expr_only: bool,
456 span: Span
223e47cc
LB
457}
458
1a4d82fc
JJ
459impl 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
505impl 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
560pub 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)]
565pub 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.
575pub 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
635impl 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
665pub type NamedSyntaxExtension = (Name, SyntaxExtension);
666
9e0c209e
SL
667pub 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
689pub enum Determinacy {
690 Determined,
691 Undetermined,
970d7e83
LB
692}
693
9e0c209e
SL
694pub struct DummyResolver;
695
696impl 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)]
720pub struct ModuleData {
721 pub mod_path: Vec<ast::Ident>,
722 pub directory: PathBuf,
723}
724
725#[derive(Clone)]
726pub 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
737pub 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
747impl<'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 918pub 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 938pub 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).
948pub 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
959pub 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.
982pub 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}