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.
14 use codemap::{CodeMap, Span, ExpnInfo};
20 use parse::token::{InternedString, intern, str_to_ident};
22 use util::small_vector::SmallVector;
26 use std::collections::HashMap;
27 use std::gc::{Gc, GC};
30 // new-style macro! tt code:
32 // MacResult, NormalTT, IdentTT
34 // also note that ast::Mac used to have a bunch of extraneous cases and
35 // is now probably a redundant AST node, can be merged with
40 pub ext: SyntaxExtension
43 pub trait ItemDecorator {
47 meta_item: &ast::MetaItem,
49 push: |P<ast::Item>|);
52 impl ItemDecorator for fn(&mut ExtCtxt, Span, &ast::MetaItem, &ast::Item, |P<ast::Item>|) {
56 meta_item: &ast::MetaItem,
58 push: |P<ast::Item>|) {
59 (*self)(ecx, sp, meta_item, item, push)
63 pub trait ItemModifier {
67 meta_item: &ast::MetaItem,
72 impl ItemModifier for fn(&mut ExtCtxt, Span, &ast::MetaItem, P<ast::Item>) -> P<ast::Item> {
76 meta_item: &ast::MetaItem,
79 (*self)(ecx, span, meta_item, item)
83 /// Represents a thing that maps token trees to Macro Results
84 pub trait TTMacroExpander {
86 ecx: &'cx mut ExtCtxt,
88 token_tree: &[ast::TokenTree])
89 -> Box<MacResult+'cx>;
92 pub type MacroExpanderFn =
93 fn<'cx>(&'cx mut ExtCtxt, Span, &[ast::TokenTree]) -> Box<MacResult+'cx>;
95 impl TTMacroExpander for MacroExpanderFn {
97 ecx: &'cx mut ExtCtxt,
99 token_tree: &[ast::TokenTree])
100 -> Box<MacResult+'cx> {
101 (*self)(ecx, span, token_tree)
105 pub trait IdentMacroExpander {
106 fn expand<'cx>(&self,
107 cx: &'cx mut ExtCtxt,
110 token_tree: Vec<ast::TokenTree> )
111 -> Box<MacResult+'cx>;
114 pub type IdentMacroExpanderFn =
115 fn<'cx>(&'cx mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree>) -> Box<MacResult+'cx>;
117 impl IdentMacroExpander for IdentMacroExpanderFn {
118 fn expand<'cx>(&self,
119 cx: &'cx mut ExtCtxt,
122 token_tree: Vec<ast::TokenTree> )
123 -> Box<MacResult+'cx> {
124 (*self)(cx, sp, ident, token_tree)
128 /// The result of a macro expansion. The return values of the various
129 /// methods are spliced into the AST at the callsite of the macro (or
130 /// just into the compiler's internal macro table, for `make_def`).
131 pub trait MacResult {
132 /// Attempt to define a new macro.
133 // this should go away; the idea that a macro might expand into
134 // either a macro definition or an expression, depending on what
135 // the context wants, is kind of silly.
136 fn make_def(&mut self) -> Option<MacroDef> {
139 /// Create an expression.
140 fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
143 /// Create zero or more items.
144 fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
148 /// Create zero or more methods.
149 fn make_methods(self: Box<Self>) -> Option<SmallVector<P<ast::Method>>> {
153 /// Create a pattern.
154 fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> {
158 /// Create a statement.
160 /// By default this attempts to create an expression statement,
161 /// returning None if that fails.
162 fn make_stmt(self: Box<Self>) -> Option<P<ast::Stmt>> {
164 .map(|e| P(codemap::respan(e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID))))
168 /// A convenience type for macros that return a single expression.
173 pub fn new(e: P<ast::Expr>) -> Box<MacResult+'static> {
174 box MacExpr { e: e } as Box<MacResult+'static>
177 impl MacResult for MacExpr {
178 fn make_expr(self: Box<MacExpr>) -> Option<P<ast::Expr>> {
181 fn make_pat(self: Box<MacExpr>) -> Option<P<ast::Pat>> {
183 ast::ExprLit(_) => Some(P(ast::Pat {
184 id: ast::DUMMY_NODE_ID,
186 node: ast::PatLit(self.e)
192 /// A convenience type for macros that return a single pattern.
197 pub fn new(p: P<ast::Pat>) -> Box<MacResult+'static> {
198 box MacPat { p: p } as Box<MacResult+'static>
201 impl MacResult for MacPat {
202 fn make_pat(self: Box<MacPat>) -> Option<P<ast::Pat>> {
206 /// A convenience type for macros that return a single item.
211 pub fn new(i: P<ast::Item>) -> Box<MacResult+'static> {
212 box MacItem { i: i } as Box<MacResult+'static>
215 impl MacResult for MacItem {
216 fn make_items(self: Box<MacItem>) -> Option<SmallVector<P<ast::Item>>> {
217 Some(SmallVector::one(self.i))
219 fn make_stmt(self: Box<MacItem>) -> Option<P<ast::Stmt>> {
220 Some(P(codemap::respan(
223 P(codemap::respan(self.i.span, ast::DeclItem(self.i))),
224 ast::DUMMY_NODE_ID))))
228 /// Fill-in macro expansion result, to allow compilation to continue
229 /// after hitting errors.
230 pub struct DummyResult {
236 /// Create a default MacResult that can be anything.
238 /// Use this as a return value after hitting any errors and
239 /// calling `span_err`.
240 pub fn any(sp: Span) -> Box<MacResult+'static> {
241 box DummyResult { expr_only: false, span: sp } as Box<MacResult+'static>
244 /// Create a default MacResult that can only be an expression.
246 /// Use this for macros that must expand to an expression, so even
247 /// if an error is encountered internally, the user will receive
248 /// an error that they also used it in the wrong place.
249 pub fn expr(sp: Span) -> Box<MacResult+'static> {
250 box DummyResult { expr_only: true, span: sp } as Box<MacResult+'static>
253 /// A plain dummy expression.
254 pub fn raw_expr(sp: Span) -> P<ast::Expr> {
256 id: ast::DUMMY_NODE_ID,
257 node: ast::ExprLit(P(codemap::respan(sp, ast::LitNil))),
262 /// A plain dummy pattern.
263 pub fn raw_pat(sp: Span) -> ast::Pat {
265 id: ast::DUMMY_NODE_ID,
266 node: ast::PatWild(ast::PatWildSingle),
273 impl MacResult for DummyResult {
274 fn make_expr(self: Box<DummyResult>) -> Option<P<ast::Expr>> {
275 Some(DummyResult::raw_expr(self.span))
277 fn make_pat(self: Box<DummyResult>) -> Option<P<ast::Pat>> {
278 Some(P(DummyResult::raw_pat(self.span)))
280 fn make_items(self: Box<DummyResult>) -> Option<SmallVector<P<ast::Item>>> {
281 // this code needs a comment... why not always just return the Some() ?
285 Some(SmallVector::zero())
288 fn make_methods(self: Box<DummyResult>) -> Option<SmallVector<P<ast::Method>>> {
292 Some(SmallVector::zero())
295 fn make_stmt(self: Box<DummyResult>) -> Option<P<ast::Stmt>> {
296 Some(P(codemap::respan(self.span,
297 ast::StmtExpr(DummyResult::raw_expr(self.span),
298 ast::DUMMY_NODE_ID))))
302 /// An enum representing the different kinds of syntax extensions.
303 pub enum SyntaxExtension {
304 /// A syntax extension that is attached to an item and creates new items
307 /// `#[deriving(...)]` is an `ItemDecorator`.
308 ItemDecorator(Box<ItemDecorator + 'static>),
310 /// A syntax extension that is attached to an item and modifies it
312 ItemModifier(Box<ItemModifier + 'static>),
314 /// A normal, function-like syntax extension.
316 /// `bytes!` is a `NormalTT`.
317 NormalTT(Box<TTMacroExpander + 'static>, Option<Span>),
319 /// A function-like syntax extension that has an extra ident before
322 IdentTT(Box<IdentMacroExpander + 'static>, Option<Span>),
324 /// An ident macro that has two properties:
325 /// - it adds a macro definition to the environment, and
326 /// - the definition it adds doesn't introduce any new
329 /// `macro_rules!` is a LetSyntaxTT
330 LetSyntaxTT(Box<IdentMacroExpander + 'static>, Option<Span>),
333 pub type NamedSyntaxExtension = (Name, SyntaxExtension);
335 pub struct BlockInfo {
336 /// Should macros escape from this scope?
337 pub macros_escape: bool,
338 /// What are the pending renames?
339 pub pending_renames: mtwt::RenameList,
343 pub fn new() -> BlockInfo {
345 macros_escape: false,
346 pending_renames: Vec::new(),
351 /// The base map of methods for expanding syntax extension
352 /// AST nodes into full ASTs
353 fn initial_syntax_expander_table() -> SyntaxEnv {
354 // utility function to simplify creating NormalTT syntax extensions
355 fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
356 NormalTT(box f, None)
359 let mut syntax_expanders = SyntaxEnv::new();
360 syntax_expanders.insert(intern("macro_rules"),
361 LetSyntaxTT(box ext::tt::macro_rules::add_new_extension, None));
362 syntax_expanders.insert(intern("fmt"),
363 builtin_normal_expander(
364 ext::fmt::expand_syntax_ext));
365 syntax_expanders.insert(intern("format_args"),
366 builtin_normal_expander(
367 ext::format::expand_format_args));
368 syntax_expanders.insert(intern("format_args_method"),
369 builtin_normal_expander(
370 ext::format::expand_format_args_method));
371 syntax_expanders.insert(intern("env"),
372 builtin_normal_expander(
373 ext::env::expand_env));
374 syntax_expanders.insert(intern("option_env"),
375 builtin_normal_expander(
376 ext::env::expand_option_env));
377 syntax_expanders.insert(intern("bytes"),
378 builtin_normal_expander(
379 ext::bytes::expand_syntax_ext));
380 syntax_expanders.insert(intern("concat_idents"),
381 builtin_normal_expander(
382 ext::concat_idents::expand_syntax_ext));
383 syntax_expanders.insert(intern("concat"),
384 builtin_normal_expander(
385 ext::concat::expand_syntax_ext));
386 syntax_expanders.insert(intern("log_syntax"),
387 builtin_normal_expander(
388 ext::log_syntax::expand_syntax_ext));
389 syntax_expanders.insert(intern("deriving"),
390 ItemDecorator(box ext::deriving::expand_meta_deriving));
392 // Quasi-quoting expanders
393 syntax_expanders.insert(intern("quote_tokens"),
394 builtin_normal_expander(
395 ext::quote::expand_quote_tokens));
396 syntax_expanders.insert(intern("quote_expr"),
397 builtin_normal_expander(
398 ext::quote::expand_quote_expr));
399 syntax_expanders.insert(intern("quote_ty"),
400 builtin_normal_expander(
401 ext::quote::expand_quote_ty));
402 syntax_expanders.insert(intern("quote_method"),
403 builtin_normal_expander(
404 ext::quote::expand_quote_method));
405 syntax_expanders.insert(intern("quote_item"),
406 builtin_normal_expander(
407 ext::quote::expand_quote_item));
408 syntax_expanders.insert(intern("quote_pat"),
409 builtin_normal_expander(
410 ext::quote::expand_quote_pat));
411 syntax_expanders.insert(intern("quote_arm"),
412 builtin_normal_expander(
413 ext::quote::expand_quote_arm));
414 syntax_expanders.insert(intern("quote_stmt"),
415 builtin_normal_expander(
416 ext::quote::expand_quote_stmt));
418 syntax_expanders.insert(intern("line"),
419 builtin_normal_expander(
420 ext::source_util::expand_line));
421 syntax_expanders.insert(intern("col"),
422 builtin_normal_expander(
423 ext::source_util::expand_col));
424 syntax_expanders.insert(intern("file"),
425 builtin_normal_expander(
426 ext::source_util::expand_file));
427 syntax_expanders.insert(intern("stringify"),
428 builtin_normal_expander(
429 ext::source_util::expand_stringify));
430 syntax_expanders.insert(intern("include"),
431 builtin_normal_expander(
432 ext::source_util::expand_include));
433 syntax_expanders.insert(intern("include_str"),
434 builtin_normal_expander(
435 ext::source_util::expand_include_str));
436 syntax_expanders.insert(intern("include_bin"),
437 builtin_normal_expander(
438 ext::source_util::expand_include_bin));
439 syntax_expanders.insert(intern("module_path"),
440 builtin_normal_expander(
441 ext::source_util::expand_mod));
442 syntax_expanders.insert(intern("asm"),
443 builtin_normal_expander(
444 ext::asm::expand_asm));
445 syntax_expanders.insert(intern("cfg"),
446 builtin_normal_expander(
447 ext::cfg::expand_cfg));
448 syntax_expanders.insert(intern("trace_macros"),
449 builtin_normal_expander(
450 ext::trace_macros::expand_trace_macros));
454 /// One of these is made during expansion and incrementally updated as we go;
455 /// when a macro expansion occurs, the resulting nodes have the backtrace()
456 /// -> expn_info of their expansion context stored into their span.
457 pub struct ExtCtxt<'a> {
458 pub parse_sess: &'a parse::ParseSess,
459 pub cfg: ast::CrateConfig,
460 pub backtrace: Option<Gc<ExpnInfo>>,
461 pub ecfg: expand::ExpansionConfig,
463 pub mod_path: Vec<ast::Ident> ,
465 pub exported_macros: Vec<P<ast::Item>>,
467 pub syntax_env: SyntaxEnv,
470 impl<'a> ExtCtxt<'a> {
471 pub fn new<'a>(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig,
472 ecfg: expand::ExpansionConfig) -> ExtCtxt<'a> {
474 parse_sess: parse_sess,
477 mod_path: Vec::new(),
480 exported_macros: Vec::new(),
481 syntax_env: initial_syntax_expander_table(),
485 #[deprecated = "Replaced with `expander().fold_expr()`"]
486 pub fn expand_expr(&mut self, e: P<ast::Expr>) -> P<ast::Expr> {
487 self.expander().fold_expr(e)
490 /// Returns a `Folder` for deeply expanding all macros in a AST node.
491 pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
492 expand::MacroExpander { cx: self }
495 pub fn new_parser_from_tts(&self, tts: &[ast::TokenTree])
496 -> parser::Parser<'a> {
497 parse::tts_to_parser(self.parse_sess, Vec::from_slice(tts), self.cfg())
500 pub fn codemap(&self) -> &'a CodeMap { &self.parse_sess.span_diagnostic.cm }
501 pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
502 pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
503 pub fn call_site(&self) -> Span {
504 match self.backtrace {
505 Some(expn_info) => expn_info.call_site,
506 None => self.bug("missing top span")
509 pub fn print_backtrace(&self) { }
510 pub fn backtrace(&self) -> Option<Gc<ExpnInfo>> { self.backtrace }
511 pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }
512 pub fn mod_pop(&mut self) { self.mod_path.pop().unwrap(); }
513 pub fn mod_path(&self) -> Vec<ast::Ident> {
514 let mut v = Vec::new();
515 v.push(token::str_to_ident(self.ecfg.crate_name.as_slice()));
516 v.extend(self.mod_path.iter().map(|a| *a));
519 pub fn bt_push(&mut self, ei: codemap::ExpnInfo) {
521 ExpnInfo {call_site: cs, callee: ref callee} => {
523 Some(box(GC) ExpnInfo {
524 call_site: Span {lo: cs.lo, hi: cs.hi,
525 expn_info: self.backtrace.clone()},
526 callee: (*callee).clone()
531 pub fn bt_pop(&mut self) {
532 match self.backtrace {
533 Some(expn_info) => self.backtrace = expn_info.call_site.expn_info,
534 _ => self.bug("tried to pop without a push")
537 /// Emit `msg` attached to `sp`, and stop compilation immediately.
539 /// `span_err` should be strongly preferred where-ever possible:
540 /// this should *only* be used when
541 /// - continuing has a high risk of flow-on errors (e.g. errors in
542 /// declaring a macro would cause all uses of that macro to
543 /// complain about "undefined macro"), or
544 /// - there is literally nothing else that can be done (however,
545 /// in most cases one can construct a dummy expression/item to
546 /// substitute; we never hit resolve/type-checking so the dummy
547 /// value doesn't have to match anything)
548 pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
549 self.print_backtrace();
550 self.parse_sess.span_diagnostic.span_fatal(sp, msg);
553 /// Emit `msg` attached to `sp`, without immediately stopping
556 /// Compilation will be stopped in the near future (at the end of
557 /// the macro expansion phase).
558 pub fn span_err(&self, sp: Span, msg: &str) {
559 self.print_backtrace();
560 self.parse_sess.span_diagnostic.span_err(sp, msg);
562 pub fn span_warn(&self, sp: Span, msg: &str) {
563 self.print_backtrace();
564 self.parse_sess.span_diagnostic.span_warn(sp, msg);
566 pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
567 self.print_backtrace();
568 self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
570 pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
571 self.print_backtrace();
572 self.parse_sess.span_diagnostic.span_bug(sp, msg);
574 pub fn span_note(&self, sp: Span, msg: &str) {
575 self.print_backtrace();
576 self.parse_sess.span_diagnostic.span_note(sp, msg);
578 pub fn bug(&self, msg: &str) -> ! {
579 self.print_backtrace();
580 self.parse_sess.span_diagnostic.handler().bug(msg);
582 pub fn trace_macros(&self) -> bool {
585 pub fn set_trace_macros(&mut self, x: bool) {
588 pub fn ident_of(&self, st: &str) -> ast::Ident {
591 pub fn name_of(&self, st: &str) -> ast::Name {
596 /// Extract a string literal from the macro expanded version of `expr`,
597 /// emitting `err_msg` if `expr` is not a string literal. This does not stop
598 /// compilation on error, merely emits a non-fatal error and returns None.
599 pub fn expr_to_string(cx: &mut ExtCtxt, expr: P<ast::Expr>, err_msg: &str)
600 -> Option<(InternedString, ast::StrStyle)> {
601 // we want to be able to handle e.g. concat("foo", "bar")
602 let expr = cx.expander().fold_expr(expr);
604 ast::ExprLit(ref l) => match l.node {
605 ast::LitStr(ref s, style) => return Some(((*s).clone(), style)),
606 _ => cx.span_err(l.span, err_msg)
608 _ => cx.span_err(expr.span, err_msg)
613 /// Non-fatally assert that `tts` is empty. Note that this function
614 /// returns even when `tts` is non-empty, macros that *need* to stop
615 /// compilation should call
616 /// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be
617 /// done as rarely as possible).
618 pub fn check_zero_tts(cx: &ExtCtxt,
620 tts: &[ast::TokenTree],
623 cx.span_err(sp, format!("{} takes no arguments", name).as_slice());
627 /// Extract the string literal from the first token of `tts`. If this
628 /// is not a string literal, emit an error and return None.
629 pub fn get_single_str_from_tts(cx: &ExtCtxt,
631 tts: &[ast::TokenTree],
635 cx.span_err(sp, format!("{} takes 1 argument.", name).as_slice());
638 ast::TTTok(_, token::LIT_STR(ident)) => return Some(parse::str_lit(ident.as_str())),
639 ast::TTTok(_, token::LIT_STR_RAW(ident, _)) => {
640 return Some(parse::raw_str_lit(ident.as_str()))
644 format!("{} requires a string.", name).as_slice())
651 /// Extract comma-separated expressions from `tts`. If there is a
652 /// parsing error, emit a non-fatal error and return None.
653 pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
655 tts: &[ast::TokenTree]) -> Option<Vec<P<ast::Expr>>> {
656 let mut p = cx.new_parser_from_tts(tts);
657 let mut es = Vec::new();
658 while p.token != token::EOF {
659 es.push(cx.expander().fold_expr(p.parse_expr()));
660 if p.eat(&token::COMMA) {
663 if p.token != token::EOF {
664 cx.span_err(sp, "expected token: `,`");
671 /// In order to have some notion of scoping for macros,
672 /// we want to implement the notion of a transformation
675 /// This environment maps Names to SyntaxExtensions.
676 pub struct SyntaxEnv {
677 chain: Vec<MapChainFrame> ,
680 // impl question: how to implement it? Initially, the
681 // env will contain only macros, so it might be painful
682 // to add an empty frame for every context. Let's just
683 // get it working, first....
685 // NB! the mutability of the underlying maps means that
686 // if expansion is out-of-order, a deeper scope may be
687 // able to refer to a macro that was added to an enclosing
688 // scope lexically later than the deeper scope.
690 struct MapChainFrame {
692 map: HashMap<Name, Rc<SyntaxExtension>>,
696 fn new() -> SyntaxEnv {
697 let mut map = SyntaxEnv { chain: Vec::new() };
702 pub fn push_frame(&mut self) {
703 self.chain.push(MapChainFrame {
704 info: BlockInfo::new(),
709 pub fn pop_frame(&mut self) {
710 assert!(self.chain.len() > 1, "too many pops on MapChain!");
714 fn find_escape_frame<'a>(&'a mut self) -> &'a mut MapChainFrame {
715 for (i, frame) in self.chain.mut_iter().enumerate().rev() {
716 if !frame.info.macros_escape || i == 0 {
723 pub fn find(&self, k: &Name) -> Option<Rc<SyntaxExtension>> {
724 for frame in self.chain.iter().rev() {
725 match frame.map.find(k) {
726 Some(v) => return Some(v.clone()),
733 pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
734 self.find_escape_frame().map.insert(k, Rc::new(v));
737 pub fn info<'a>(&'a mut self) -> &'a mut BlockInfo {
738 let last_chain_index = self.chain.len() - 1;
739 &mut self.chain.get_mut(last_chain_index).info