1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
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.
11 use ast
::{Block, Ident, Mac_, PatKind}
;
12 use ast
::{Name, MacStmtStyle, StmtKind, ItemKind}
;
14 use ext
::hygiene
::Mark
;
15 use ext
::placeholders
::{placeholder, PlaceholderExpander}
;
16 use attr
::{self, HasAttrs}
;
17 use codemap
::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}
;
18 use syntax_pos
::{self, Span, ExpnId}
;
19 use config
::{is_test_or_bench, StripUnconfigured}
;
21 use feature_gate
::{self, Features}
;
24 use parse
::{ParseSess, PResult, lexer}
;
25 use parse
::parser
::Parser
;
26 use parse
::token
::{self, intern, keywords}
;
30 use tokenstream
::{TokenTree, TokenStream}
;
31 use util
::small_vector
::SmallVector
;
35 use std
::path
::PathBuf
;
38 macro_rules
! expansions
{
39 ($
($kind
:ident
: $ty
:ty
[$
($vec
:ident
, $ty_elt
:ty
)*], $kind_name
:expr
, .$make
:ident
,
40 $
(.$fold
:ident
)* $
(lift
.$fold_elt
:ident
)*,
41 $
(.$visit
:ident
)* $
(lift
.$visit_elt
:ident
)*;)*) => {
42 #[derive(Copy, Clone, PartialEq, Eq)]
43 pub enum ExpansionKind { OptExpr, $( $kind, )* }
44 pub enum Expansion { OptExpr(Option<P<ast::Expr>>), $( $kind($ty), )* }
47 pub fn name(self) -> &'
static str {
49 ExpansionKind
::OptExpr
=> "expression",
50 $
( ExpansionKind
::$kind
=> $kind_name
, )*
54 fn make_from
<'a
>(self, result
: Box
<MacResult
+ 'a
>) -> Option
<Expansion
> {
56 ExpansionKind
::OptExpr
=> result
.make_expr().map(Some
).map(Expansion
::OptExpr
),
57 $
( ExpansionKind
::$kind
=> result
.$
make().map(Expansion
::$kind
), )*
63 pub fn make_opt_expr(self) -> Option
<P
<ast
::Expr
>> {
65 Expansion
::OptExpr(expr
) => expr
,
66 _
=> panic
!("Expansion::make_* called on the wrong kind of expansion"),
69 $
( pub fn $
make(self) -> $ty
{
71 Expansion
::$
kind(ast
) => ast
,
72 _
=> panic
!("Expansion::make_* called on the wrong kind of expansion"),
76 pub fn fold_with
<F
: Folder
>(self, folder
: &mut F
) -> Self {
77 use self::Expansion
::*;
79 OptExpr(expr
) => OptExpr(expr
.and_then(|expr
| folder
.fold_opt_expr(expr
))),
80 $
($
( $
kind(ast
) => $
kind(folder
.$
fold(ast
)), )*)*
82 $
kind(ast
.into_iter().flat_map(|ast
| folder
.$
fold_elt(ast
)).collect())
87 pub fn visit_with
<V
: Visitor
>(&self, visitor
: &mut V
) {
89 Expansion
::OptExpr(Some(ref expr
)) => visitor
.visit_expr(expr
),
90 Expansion
::OptExpr(None
) => {}
91 $
($
( Expansion
::$
kind(ref ast
) => visitor
.$
visit(ast
), )*)*
92 $
($
( Expansion
::$
kind(ref ast
) => for ast
in ast
.as_slice() {
93 visitor
.$
visit_elt(ast
);
99 impl<'a
, 'b
> Folder
for MacroExpander
<'a
, 'b
> {
100 fn fold_opt_expr(&mut self, expr
: P
<ast
::Expr
>) -> Option
<P
<ast
::Expr
>> {
101 self.expand(Expansion
::OptExpr(Some(expr
))).make_opt_expr()
103 $
($
(fn $
fold(&mut self, node
: $ty
) -> $ty
{
104 self.expand(Expansion
::$
kind(node
)).$
make()
106 $
($
(fn $
fold_elt(&mut self, node
: $ty_elt
) -> $ty
{
107 self.expand(Expansion
::$
kind(SmallVector
::one(node
))).$
make()
111 impl<'a
> MacResult
for ::ext
::tt
::macro_rules
::ParserAnyMacro
<'a
> {
112 $
(fn $
make(self: Box
<::ext
::tt
::macro_rules
::ParserAnyMacro
<'a
>>) -> Option
<$ty
> {
113 Some(self.make(ExpansionKind
::$kind
).$
make())
120 Expr
: P
<ast
::Expr
> [], "expression", .make_expr
, .fold_expr
, .visit_expr
;
121 Pat
: P
<ast
::Pat
> [], "pattern", .make_pat
, .fold_pat
, .visit_pat
;
122 Ty
: P
<ast
::Ty
> [], "type", .make_ty
, .fold_ty
, .visit_ty
;
123 Stmts
: SmallVector
<ast
::Stmt
> [SmallVector
, ast
::Stmt
],
124 "statement", .make_stmts
, lift
.fold_stmt
, lift
.visit_stmt
;
125 Items
: SmallVector
<P
<ast
::Item
>> [SmallVector
, P
<ast
::Item
>],
126 "item", .make_items
, lift
.fold_item
, lift
.visit_item
;
127 TraitItems
: SmallVector
<ast
::TraitItem
> [SmallVector
, ast
::TraitItem
],
128 "trait item", .make_trait_items
, lift
.fold_trait_item
, lift
.visit_trait_item
;
129 ImplItems
: SmallVector
<ast
::ImplItem
> [SmallVector
, ast
::ImplItem
],
130 "impl item", .make_impl_items
, lift
.fold_impl_item
, lift
.visit_impl_item
;
134 fn dummy(self, span
: Span
) -> Expansion
{
135 self.make_from(DummyResult
::any(span
)).unwrap()
138 fn expect_from_annotatables
<I
: IntoIterator
<Item
= Annotatable
>>(self, items
: I
) -> Expansion
{
139 let items
= items
.into_iter();
141 ExpansionKind
::Items
=>
142 Expansion
::Items(items
.map(Annotatable
::expect_item
).collect()),
143 ExpansionKind
::ImplItems
=>
144 Expansion
::ImplItems(items
.map(Annotatable
::expect_impl_item
).collect()),
145 ExpansionKind
::TraitItems
=>
146 Expansion
::TraitItems(items
.map(Annotatable
::expect_trait_item
).collect()),
152 pub struct Invocation
{
153 pub kind
: InvocationKind
,
154 expansion_kind
: ExpansionKind
,
155 expansion_data
: ExpansionData
,
158 pub enum InvocationKind
{
160 attrs
: Vec
<ast
::Attribute
>,
162 ident
: Option
<Ident
>,
166 attr
: ast
::Attribute
,
172 fn span(&self) -> Span
{
174 InvocationKind
::Bang { span, .. }
=> span
,
175 InvocationKind
::Attr { ref attr, .. }
=> attr
.span
,
180 pub struct MacroExpander
<'a
, 'b
:'a
> {
181 pub cx
: &'a
mut ExtCtxt
<'b
>,
182 monotonic
: bool
, // c.f. `cx.monotonic_expander()`
185 impl<'a
, 'b
> MacroExpander
<'a
, 'b
> {
186 pub fn new(cx
: &'a
mut ExtCtxt
<'b
>, monotonic
: bool
) -> Self {
187 MacroExpander { cx: cx, monotonic: monotonic }
190 pub fn expand_crate(&mut self, mut krate
: ast
::Crate
) -> ast
::Crate
{
191 self.cx
.crate_root
= std_inject
::injected_crate_name(&krate
);
192 let mut module
= ModuleData
{
193 mod_path
: vec
![token
::str_to_ident(&self.cx
.ecfg
.crate_name
)],
194 directory
: PathBuf
::from(self.cx
.codemap().span_to_filename(krate
.span
)),
196 module
.directory
.pop();
197 self.cx
.current_expansion
.module
= Rc
::new(module
);
199 let krate_item
= Expansion
::Items(SmallVector
::one(P(ast
::Item
{
202 node
: ast
::ItemKind
::Mod(krate
.module
),
203 ident
: keywords
::Invalid
.ident(),
204 id
: ast
::DUMMY_NODE_ID
,
205 vis
: ast
::Visibility
::Public
,
208 match self.expand(krate_item
).make_items().pop().unwrap().unwrap() {
209 ast
::Item { attrs, node: ast::ItemKind::Mod(module), .. }
=> {
211 krate
.module
= module
;
219 // Fully expand all the invocations in `expansion`.
220 fn expand(&mut self, expansion
: Expansion
) -> Expansion
{
221 let orig_expansion_data
= self.cx
.current_expansion
.clone();
222 self.cx
.current_expansion
.depth
= 0;
224 let (expansion
, mut invocations
) = self.collect_invocations(expansion
);
225 invocations
.reverse();
227 let mut expansions
= Vec
::new();
228 let mut undetermined_invocations
= Vec
::new();
229 let (mut progress
, mut force
) = (false, !self.monotonic
);
231 let invoc
= if let Some(invoc
) = invocations
.pop() {
233 } else if undetermined_invocations
.is_empty() {
236 invocations
= mem
::replace(&mut undetermined_invocations
, Vec
::new());
237 force
= !mem
::replace(&mut progress
, false);
242 if self.monotonic { invoc.expansion_data.mark }
else { orig_expansion_data.mark }
;
243 let resolution
= match invoc
.kind
{
244 InvocationKind
::Bang { ref mac, .. }
=> {
245 self.cx
.resolver
.resolve_macro(scope
, &mac
.node
.path
, force
)
247 InvocationKind
::Attr { ref attr, .. }
=> {
248 let ident
= ast
::Ident
::with_empty_ctxt(intern(&*attr
.name()));
249 let path
= ast
::Path
::from_ident(attr
.span
, ident
);
250 self.cx
.resolver
.resolve_macro(scope
, &path
, force
)
253 let ext
= match resolution
{
254 Ok(ext
) => Some(ext
),
255 Err(Determinacy
::Determined
) => None
,
256 Err(Determinacy
::Undetermined
) => {
257 undetermined_invocations
.push(invoc
);
263 let ExpansionData { depth, mark, .. }
= invoc
.expansion_data
;
264 self.cx
.current_expansion
= invoc
.expansion_data
.clone();
266 self.cx
.current_expansion
.mark
= scope
;
267 let expansion
= match ext
{
268 Some(ext
) => self.expand_invoc(invoc
, ext
),
269 None
=> invoc
.expansion_kind
.dummy(invoc
.span()),
272 let (expansion
, new_invocations
) = self.collect_invocations(expansion
);
274 if expansions
.len() < depth
{
275 expansions
.push(Vec
::new());
277 expansions
[depth
- 1].push((mark
.as_u32(), expansion
));
278 if !self.cx
.ecfg
.single_step
{
279 invocations
.extend(new_invocations
.into_iter().rev());
283 self.cx
.current_expansion
= orig_expansion_data
;
285 let mut placeholder_expander
= PlaceholderExpander
::new(self.cx
, self.monotonic
);
286 while let Some(expansions
) = expansions
.pop() {
287 for (mark
, expansion
) in expansions
.into_iter().rev() {
288 placeholder_expander
.add(ast
::NodeId
::from_u32(mark
), expansion
);
292 expansion
.fold_with(&mut placeholder_expander
)
295 fn collect_invocations(&mut self, expansion
: Expansion
) -> (Expansion
, Vec
<Invocation
>) {
297 let mut collector
= InvocationCollector
{
298 cfg
: StripUnconfigured
{
299 should_test
: self.cx
.ecfg
.should_test
,
300 sess
: self.cx
.parse_sess
,
301 features
: self.cx
.ecfg
.features
,
304 invocations
: Vec
::new(),
305 monotonic
: self.monotonic
,
307 (expansion
.fold_with(&mut collector
), collector
.invocations
)
311 let err_count
= self.cx
.parse_sess
.span_diagnostic
.err_count();
312 let mark
= self.cx
.current_expansion
.mark
;
313 self.cx
.resolver
.visit_expansion(mark
, &result
.0);
314 self.cx
.resolve_err_count
+= self.cx
.parse_sess
.span_diagnostic
.err_count() - err_count
;
320 fn expand_invoc(&mut self, invoc
: Invocation
, ext
: Rc
<SyntaxExtension
>) -> Expansion
{
322 InvocationKind
::Bang { .. }
=> self.expand_bang_invoc(invoc
, ext
),
323 InvocationKind
::Attr { .. }
=> self.expand_attr_invoc(invoc
, ext
),
327 fn expand_attr_invoc(&mut self, invoc
: Invocation
, ext
: Rc
<SyntaxExtension
>) -> Expansion
{
328 let Invocation { expansion_kind: kind, .. }
= invoc
;
329 let (attr
, item
) = match invoc
.kind
{
330 InvocationKind
::Attr { attr, item }
=> (attr
, item
),
334 attr
::mark_used(&attr
);
335 let name
= intern(&attr
.name());
336 self.cx
.bt_push(ExpnInfo
{
337 call_site
: attr
.span
,
338 callee
: NameAndSpan
{
339 format
: MacroAttribute(name
),
340 span
: Some(attr
.span
),
341 allow_internal_unstable
: false,
346 MultiModifier(ref mac
) => {
347 let item
= mac
.expand(self.cx
, attr
.span
, &attr
.node
.value
, item
);
348 kind
.expect_from_annotatables(item
)
350 MultiDecorator(ref mac
) => {
351 let mut items
= Vec
::new();
352 mac
.expand(self.cx
, attr
.span
, &attr
.node
.value
, &item
,
353 &mut |item
| items
.push(item
));
355 kind
.expect_from_annotatables(items
)
357 SyntaxExtension
::AttrProcMacro(ref mac
) => {
358 let attr_toks
= TokenStream
::from_tts(tts_for_attr(&attr
, &self.cx
.parse_sess
));
359 let item_toks
= TokenStream
::from_tts(tts_for_item(&item
, &self.cx
.parse_sess
));
361 let tok_result
= mac
.expand(self.cx
, attr
.span
, attr_toks
, item_toks
);
362 self.parse_expansion(tok_result
, kind
, name
, attr
.span
)
364 SyntaxExtension
::CustomDerive(_
) => {
365 self.cx
.span_err(attr
.span
, &format
!("`{}` is a derive mode", name
));
366 kind
.dummy(attr
.span
)
369 let msg
= &format
!("macro `{}` may not be used in attributes", name
);
370 self.cx
.span_err(attr
.span
, &msg
);
371 kind
.dummy(attr
.span
)
376 /// Expand a macro invocation. Returns the result of expansion.
377 fn expand_bang_invoc(&mut self, invoc
: Invocation
, ext
: Rc
<SyntaxExtension
>) -> Expansion
{
378 let (mark
, kind
) = (invoc
.expansion_data
.mark
, invoc
.expansion_kind
);
379 let (attrs
, mac
, ident
, span
) = match invoc
.kind
{
380 InvocationKind
::Bang { attrs, mac, ident, span }
=> (attrs
, mac
, ident
, span
),
383 let Mac_ { path, tts, .. }
= mac
.node
;
385 // Detect use of feature-gated or invalid attributes on macro invoations
386 // since they will not be detected after macro expansion.
387 for attr
in attrs
.iter() {
388 feature_gate
::check_attribute(&attr
, &self.cx
.parse_sess
,
389 &self.cx
.parse_sess
.codemap(),
390 &self.cx
.ecfg
.features
.unwrap());
393 if path
.segments
.len() > 1 || path
.global
|| !path
.segments
[0].parameters
.is_empty() {
394 self.cx
.span_err(path
.span
, "expected macro name without module separators");
395 return kind
.dummy(span
);
398 let extname
= path
.segments
[0].identifier
.name
;
399 let ident
= ident
.unwrap_or(keywords
::Invalid
.ident());
400 let marked_tts
= mark_tts(&tts
, mark
);
401 let opt_expanded
= match *ext
{
402 NormalTT(ref expandfun
, exp_span
, allow_internal_unstable
) => {
403 if ident
.name
!= keywords
::Invalid
.name() {
405 format
!("macro {}! expects no ident argument, given '{}'", extname
, ident
);
406 self.cx
.span_err(path
.span
, &msg
);
407 return kind
.dummy(span
);
410 self.cx
.bt_push(ExpnInfo
{
412 callee
: NameAndSpan
{
413 format
: MacroBang(extname
),
415 allow_internal_unstable
: allow_internal_unstable
,
419 kind
.make_from(expandfun
.expand(self.cx
, span
, &marked_tts
))
422 IdentTT(ref expander
, tt_span
, allow_internal_unstable
) => {
423 if ident
.name
== keywords
::Invalid
.name() {
424 self.cx
.span_err(path
.span
,
425 &format
!("macro {}! expects an ident argument", extname
));
426 return kind
.dummy(span
);
429 self.cx
.bt_push(ExpnInfo
{
431 callee
: NameAndSpan
{
432 format
: MacroBang(extname
),
434 allow_internal_unstable
: allow_internal_unstable
,
438 kind
.make_from(expander
.expand(self.cx
, span
, ident
, marked_tts
, attrs
))
441 MultiDecorator(..) | MultiModifier(..) | SyntaxExtension
::AttrProcMacro(..) => {
442 self.cx
.span_err(path
.span
,
443 &format
!("`{}` can only be used in attributes", extname
));
444 return kind
.dummy(span
);
447 SyntaxExtension
::CustomDerive(..) => {
448 self.cx
.span_err(path
.span
, &format
!("`{}` is a derive mode", extname
));
449 return kind
.dummy(span
);
452 SyntaxExtension
::ProcMacro(ref expandfun
) => {
453 if ident
.name
!= keywords
::Invalid
.name() {
455 format
!("macro {}! expects no ident argument, given '{}'", extname
, ident
);
456 self.cx
.span_err(path
.span
, &msg
);
457 return kind
.dummy(span
);
460 self.cx
.bt_push(ExpnInfo
{
462 callee
: NameAndSpan
{
463 format
: MacroBang(extname
),
464 // FIXME procedural macros do not have proper span info
465 // yet, when they do, we should use it here.
467 // FIXME probably want to follow macro_rules macros here.
468 allow_internal_unstable
: false,
472 let toks
= TokenStream
::from_tts(marked_tts
);
473 let tok_result
= expandfun
.expand(self.cx
, span
, toks
);
474 Some(self.parse_expansion(tok_result
, kind
, extname
, span
))
478 let expanded
= if let Some(expanded
) = opt_expanded
{
481 let msg
= format
!("non-{kind} macro in {kind} position: {name}",
482 name
= path
.segments
[0].identifier
.name
, kind
= kind
.name());
483 self.cx
.span_err(path
.span
, &msg
);
484 return kind
.dummy(span
);
487 expanded
.fold_with(&mut Marker
{
489 expn_id
: Some(self.cx
.backtrace()),
493 fn parse_expansion(&mut self, toks
: TokenStream
, kind
: ExpansionKind
, name
: Name
, span
: Span
)
495 let mut parser
= self.cx
.new_parser_from_tts(&toks
.to_tts());
496 let expansion
= match parser
.parse_expansion(kind
, false) {
497 Ok(expansion
) => expansion
,
500 return kind
.dummy(span
);
503 parser
.ensure_complete_parse(name
, kind
.name(), span
);
504 // FIXME better span info
505 expansion
.fold_with(&mut ChangeSpan { span: span }
)
509 impl<'a
> Parser
<'a
> {
510 pub fn parse_expansion(&mut self, kind
: ExpansionKind
, macro_legacy_warnings
: bool
)
511 -> PResult
<'a
, Expansion
> {
513 ExpansionKind
::Items
=> {
514 let mut items
= SmallVector
::zero();
515 while let Some(item
) = self.parse_item()?
{
518 Expansion
::Items(items
)
520 ExpansionKind
::TraitItems
=> {
521 let mut items
= SmallVector
::zero();
522 while self.token
!= token
::Eof
{
523 items
.push(self.parse_trait_item()?
);
525 Expansion
::TraitItems(items
)
527 ExpansionKind
::ImplItems
=> {
528 let mut items
= SmallVector
::zero();
529 while self.token
!= token
::Eof
{
530 items
.push(self.parse_impl_item()?
);
532 Expansion
::ImplItems(items
)
534 ExpansionKind
::Stmts
=> {
535 let mut stmts
= SmallVector
::zero();
536 while self.token
!= token
::Eof
{
537 if let Some(stmt
) = self.parse_full_stmt(macro_legacy_warnings
)?
{
541 Expansion
::Stmts(stmts
)
543 ExpansionKind
::Expr
=> Expansion
::Expr(self.parse_expr()?
),
544 ExpansionKind
::OptExpr
=> Expansion
::OptExpr(Some(self.parse_expr()?
)),
545 ExpansionKind
::Ty
=> Expansion
::Ty(self.parse_ty()?
),
546 ExpansionKind
::Pat
=> Expansion
::Pat(self.parse_pat()?
),
550 pub fn ensure_complete_parse(&mut self, macro_name
: ast
::Name
, kind_name
: &str, span
: Span
) {
551 if self.token
!= token
::Eof
{
552 let msg
= format
!("macro expansion ignores token `{}` and any following",
553 self.this_token_to_string());
554 let mut err
= self.diagnostic().struct_span_err(self.span
, &msg
);
555 let msg
= format
!("caused by the macro expansion here; the usage \
556 of `{}!` is likely invalid in {} context",
557 macro_name
, kind_name
);
558 err
.span_note(span
, &msg
).emit();
563 struct InvocationCollector
<'a
, 'b
: 'a
> {
564 cx
: &'a
mut ExtCtxt
<'b
>,
565 cfg
: StripUnconfigured
<'a
>,
566 invocations
: Vec
<Invocation
>,
570 macro_rules
! fully_configure
{
571 ($this
:ident
, $node
:ident
, $noop_fold
:ident
) => {
572 match $
noop_fold($node
, &mut $this
.cfg
).pop() {
574 None
=> return SmallVector
::zero(),
579 impl<'a
, 'b
> InvocationCollector
<'a
, 'b
> {
580 fn collect(&mut self, expansion_kind
: ExpansionKind
, kind
: InvocationKind
) -> Expansion
{
581 let mark
= Mark
::fresh();
582 self.invocations
.push(Invocation
{
584 expansion_kind
: expansion_kind
,
585 expansion_data
: ExpansionData
{
587 depth
: self.cx
.current_expansion
.depth
+ 1,
588 ..self.cx
.current_expansion
.clone()
591 placeholder(expansion_kind
, ast
::NodeId
::from_u32(mark
.as_u32()))
595 &mut self, mac
: ast
::Mac
, attrs
: Vec
<ast
::Attribute
>, span
: Span
, kind
: ExpansionKind
,
597 self.collect(kind
, InvocationKind
::Bang { attrs: attrs, mac: mac, ident: None, span: span }
)
600 fn collect_attr(&mut self, attr
: ast
::Attribute
, item
: Annotatable
, kind
: ExpansionKind
)
602 self.collect(kind
, InvocationKind
::Attr { attr: attr, item: item }
)
605 // If `item` is an attr invocation, remove and return the macro attribute.
606 fn classify_item
<T
: HasAttrs
>(&mut self, mut item
: T
) -> (T
, Option
<ast
::Attribute
>) {
608 item
= item
.map_attrs(|mut attrs
| {
609 attr
= self.cx
.resolver
.find_attr_invoc(&mut attrs
);
615 fn configure
<T
: HasAttrs
>(&mut self, node
: T
) -> Option
<T
> {
616 self.cfg
.configure(node
)
620 // These are pretty nasty. Ideally, we would keep the tokens around, linked from
621 // the AST. However, we don't so we need to create new ones. Since the item might
622 // have come from a macro expansion (possibly only in part), we can't use the
625 // Therefore, we must use the pretty printer (yuck) to turn the AST node into a
626 // string, which we then re-tokenise (double yuck), but first we have to patch
627 // the pretty-printed string on to the end of the existing codemap (infinity-yuck).
628 fn tts_for_item(item
: &Annotatable
, parse_sess
: &ParseSess
) -> Vec
<TokenTree
> {
629 let text
= match *item
{
630 Annotatable
::Item(ref i
) => pprust
::item_to_string(i
),
631 Annotatable
::TraitItem(ref ti
) => pprust
::trait_item_to_string(ti
),
632 Annotatable
::ImplItem(ref ii
) => pprust
::impl_item_to_string(ii
),
634 string_to_tts(text
, parse_sess
)
637 fn tts_for_attr(attr
: &ast
::Attribute
, parse_sess
: &ParseSess
) -> Vec
<TokenTree
> {
638 string_to_tts(pprust
::attr_to_string(attr
), parse_sess
)
641 fn string_to_tts(text
: String
, parse_sess
: &ParseSess
) -> Vec
<TokenTree
> {
642 let filemap
= parse_sess
.codemap()
643 .new_filemap(String
::from("<macro expansion>"), None
, text
);
645 let lexer
= lexer
::StringReader
::new(&parse_sess
.span_diagnostic
, filemap
);
646 let mut parser
= Parser
::new(parse_sess
, Box
::new(lexer
));
647 panictry
!(parser
.parse_all_token_trees())
650 impl<'a
, 'b
> Folder
for InvocationCollector
<'a
, 'b
> {
651 fn fold_expr(&mut self, expr
: P
<ast
::Expr
>) -> P
<ast
::Expr
> {
652 let mut expr
= self.cfg
.configure_expr(expr
).unwrap();
653 expr
.node
= self.cfg
.configure_expr_kind(expr
.node
);
655 if let ast
::ExprKind
::Mac(mac
) = expr
.node
{
656 self.collect_bang(mac
, expr
.attrs
.into(), expr
.span
, ExpansionKind
::Expr
).make_expr()
658 P(noop_fold_expr(expr
, self))
662 fn fold_opt_expr(&mut self, expr
: P
<ast
::Expr
>) -> Option
<P
<ast
::Expr
>> {
663 let mut expr
= configure
!(self, expr
).unwrap();
664 expr
.node
= self.cfg
.configure_expr_kind(expr
.node
);
666 if let ast
::ExprKind
::Mac(mac
) = expr
.node
{
667 self.collect_bang(mac
, expr
.attrs
.into(), expr
.span
, ExpansionKind
::OptExpr
)
670 Some(P(noop_fold_expr(expr
, self)))
674 fn fold_pat(&mut self, pat
: P
<ast
::Pat
>) -> P
<ast
::Pat
> {
676 PatKind
::Mac(_
) => {}
677 _
=> return noop_fold_pat(pat
, self),
680 pat
.and_then(|pat
| match pat
.node
{
682 self.collect_bang(mac
, Vec
::new(), pat
.span
, ExpansionKind
::Pat
).make_pat(),
687 fn fold_stmt(&mut self, stmt
: ast
::Stmt
) -> SmallVector
<ast
::Stmt
> {
688 let stmt
= match self.cfg
.configure_stmt(stmt
) {
690 None
=> return SmallVector
::zero(),
693 let (mac
, style
, attrs
) = if let StmtKind
::Mac(mac
) = stmt
.node
{
696 // The placeholder expander gives ids to statements, so we avoid folding the id here.
697 let ast
::Stmt { id, node, span }
= stmt
;
698 return noop_fold_stmt_kind(node
, self).into_iter().map(|node
| {
699 ast
::Stmt { id: id, node: node, span: span }
703 let mut placeholder
=
704 self.collect_bang(mac
, attrs
.into(), stmt
.span
, ExpansionKind
::Stmts
).make_stmts();
706 // If this is a macro invocation with a semicolon, then apply that
707 // semicolon to the final statement produced by expansion.
708 if style
== MacStmtStyle
::Semicolon
{
709 if let Some(stmt
) = placeholder
.pop() {
710 placeholder
.push(stmt
.add_trailing_semicolon());
717 fn fold_block(&mut self, block
: P
<Block
>) -> P
<Block
> {
718 let no_noninline_mod
= mem
::replace(&mut self.cx
.current_expansion
.no_noninline_mod
, true);
719 let result
= noop_fold_block(block
, self);
720 self.cx
.current_expansion
.no_noninline_mod
= no_noninline_mod
;
724 fn fold_item(&mut self, item
: P
<ast
::Item
>) -> SmallVector
<P
<ast
::Item
>> {
725 let item
= configure
!(self, item
);
727 let (mut item
, attr
) = self.classify_item(item
);
728 if let Some(attr
) = attr
{
729 let item
= Annotatable
::Item(fully_configure
!(self, item
, noop_fold_item
));
730 return self.collect_attr(attr
, item
, ExpansionKind
::Items
).make_items();
734 ast
::ItemKind
::Mac(..) => {
736 ItemKind
::Mac(ref mac
) => mac
.node
.path
.segments
.is_empty(),
739 return SmallVector
::one(item
);
742 item
.and_then(|item
| match item
.node
{
743 ItemKind
::Mac(mac
) => {
744 self.collect(ExpansionKind
::Items
, InvocationKind
::Bang
{
747 ident
: Some(item
.ident
),
754 ast
::ItemKind
::Mod(ast
::Mod { inner, .. }
) => {
755 if item
.ident
== keywords
::Invalid
.ident() {
756 return noop_fold_item(item
, self);
759 let orig_no_noninline_mod
= self.cx
.current_expansion
.no_noninline_mod
;
760 let mut module
= (*self.cx
.current_expansion
.module
).clone();
761 module
.mod_path
.push(item
.ident
);
763 // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`).
764 // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`).
765 // Thus, if `inner` is the dummy span, we know the module is inline.
766 let inline_module
= item
.span
.contains(inner
) || inner
== syntax_pos
::DUMMY_SP
;
769 if let Some(path
) = attr
::first_attr_value_str_by_name(&item
.attrs
, "path") {
770 self.cx
.current_expansion
.no_noninline_mod
= false;
771 module
.directory
.push(&*path
);
773 module
.directory
.push(&*item
.ident
.name
.as_str());
776 self.cx
.current_expansion
.no_noninline_mod
= false;
778 PathBuf
::from(self.cx
.parse_sess
.codemap().span_to_filename(inner
));
779 module
.directory
.pop();
783 mem
::replace(&mut self.cx
.current_expansion
.module
, Rc
::new(module
));
784 let result
= noop_fold_item(item
, self);
785 self.cx
.current_expansion
.module
= orig_module
;
786 self.cx
.current_expansion
.no_noninline_mod
= orig_no_noninline_mod
;
789 // Ensure that test functions are accessible from the test harness.
790 ast
::ItemKind
::Fn(..) if self.cx
.ecfg
.should_test
=> {
791 if item
.attrs
.iter().any(|attr
| is_test_or_bench(attr
)) {
792 item
= item
.map(|mut item
| { item.vis = ast::Visibility::Public; item }
);
794 noop_fold_item(item
, self)
796 _
=> noop_fold_item(item
, self),
800 fn fold_trait_item(&mut self, item
: ast
::TraitItem
) -> SmallVector
<ast
::TraitItem
> {
801 let item
= configure
!(self, item
);
803 let (item
, attr
) = self.classify_item(item
);
804 if let Some(attr
) = attr
{
806 Annotatable
::TraitItem(P(fully_configure
!(self, item
, noop_fold_trait_item
)));
807 return self.collect_attr(attr
, item
, ExpansionKind
::TraitItems
).make_trait_items()
811 ast
::TraitItemKind
::Macro(mac
) => {
812 let ast
::TraitItem { attrs, span, .. }
= item
;
813 self.collect_bang(mac
, attrs
, span
, ExpansionKind
::TraitItems
).make_trait_items()
815 _
=> fold
::noop_fold_trait_item(item
, self),
819 fn fold_impl_item(&mut self, item
: ast
::ImplItem
) -> SmallVector
<ast
::ImplItem
> {
820 let item
= configure
!(self, item
);
822 let (item
, attr
) = self.classify_item(item
);
823 if let Some(attr
) = attr
{
824 let item
= Annotatable
::ImplItem(P(fully_configure
!(self, item
, noop_fold_impl_item
)));
825 return self.collect_attr(attr
, item
, ExpansionKind
::ImplItems
).make_impl_items();
829 ast
::ImplItemKind
::Macro(mac
) => {
830 let ast
::ImplItem { attrs, span, .. }
= item
;
831 self.collect_bang(mac
, attrs
, span
, ExpansionKind
::ImplItems
).make_impl_items()
833 _
=> fold
::noop_fold_impl_item(item
, self),
837 fn fold_ty(&mut self, ty
: P
<ast
::Ty
>) -> P
<ast
::Ty
> {
838 let ty
= match ty
.node
{
839 ast
::TyKind
::Mac(_
) => ty
.unwrap(),
840 _
=> return fold
::noop_fold_ty(ty
, self),
844 ast
::TyKind
::Mac(mac
) =>
845 self.collect_bang(mac
, Vec
::new(), ty
.span
, ExpansionKind
::Ty
).make_ty(),
850 fn fold_foreign_mod(&mut self, foreign_mod
: ast
::ForeignMod
) -> ast
::ForeignMod
{
851 noop_fold_foreign_mod(self.cfg
.configure_foreign_mod(foreign_mod
), self)
854 fn fold_item_kind(&mut self, item
: ast
::ItemKind
) -> ast
::ItemKind
{
855 noop_fold_item_kind(self.cfg
.configure_item_kind(item
), self)
858 fn new_id(&mut self, id
: ast
::NodeId
) -> ast
::NodeId
{
860 assert_eq
!(id
, ast
::DUMMY_NODE_ID
);
861 self.cx
.resolver
.next_node_id()
868 pub struct ExpansionConfig
<'feat
> {
869 pub crate_name
: String
,
870 pub features
: Option
<&'feat Features
>,
871 pub recursion_limit
: usize,
873 pub should_test
: bool
, // If false, strip `#[test]` nodes
874 pub single_step
: bool
,
878 macro_rules
! feature_tests
{
879 ($
( fn $getter
:ident
= $field
:ident
, )*) => {
881 pub fn $
getter(&self) -> bool
{
882 match self.features
{
883 Some(&Features { $field: true, .. }
) => true,
891 impl<'feat
> ExpansionConfig
<'feat
> {
892 pub fn default(crate_name
: String
) -> ExpansionConfig
<'
static> {
894 crate_name
: crate_name
,
905 fn enable_quotes
= quote
,
907 fn enable_log_syntax
= log_syntax
,
908 fn enable_concat_idents
= concat_idents
,
909 fn enable_trace_macros
= trace_macros
,
910 fn enable_allow_internal_unstable
= allow_internal_unstable
,
911 fn enable_custom_derive
= custom_derive
,
912 fn enable_pushpop_unsafe
= pushpop_unsafe
,
913 fn enable_proc_macro
= proc_macro
,
917 // A Marker adds the given mark to the syntax context and
918 // sets spans' `expn_id` to the given expn_id (unless it is `None`).
919 struct Marker { mark: Mark, expn_id: Option<ExpnId> }
921 impl Folder
for Marker
{
922 fn fold_ident(&mut self, mut ident
: Ident
) -> Ident
{
923 ident
.ctxt
= ident
.ctxt
.apply_mark(self.mark
);
926 fn fold_mac(&mut self, mac
: ast
::Mac
) -> ast
::Mac
{
927 noop_fold_mac(mac
, self)
930 fn new_span(&mut self, mut span
: Span
) -> Span
{
931 if let Some(expn_id
) = self.expn_id
{
932 span
.expn_id
= expn_id
;
938 // apply a given mark to the given token trees. Used prior to expansion of a macro.
939 pub fn mark_tts(tts
: &[TokenTree
], m
: Mark
) -> Vec
<TokenTree
> {
940 noop_fold_tts(tts
, &mut Marker{mark:m, expn_id: None}
)