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