]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/base.rs
libsyntax: Fix errors arising from the automated `~[T]` conversion
[rust.git] / src / libsyntax / ext / base.rs
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.
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
11 use ast;
12 use ast::Name;
13 use codemap;
14 use codemap::{CodeMap, Span, ExpnInfo};
15 use ext;
16 use ext::expand;
17 use parse;
18 use parse::token;
19 use parse::token::{InternedString, intern, str_to_ident};
20 use util::small_vector::SmallVector;
21
22 use collections::HashMap;
23 use std::vec_ng::Vec;
24
25 // new-style macro! tt code:
26 //
27 //    MacResult, NormalTT, IdentTT
28 //
29 // also note that ast::Mac used to have a bunch of extraneous cases and
30 // is now probably a redundant AST node, can be merged with
31 // ast::MacInvocTT.
32
33 pub struct MacroDef {
34     name: ~str,
35     ext: SyntaxExtension
36 }
37
38 pub type ItemDecorator =
39     fn(&mut ExtCtxt, Span, @ast::MetaItem, @ast::Item, |@ast::Item|);
40
41 pub struct BasicMacroExpander {
42     expander: MacroExpanderFn,
43     span: Option<Span>
44 }
45
46 pub trait MacroExpander {
47     fn expand(&self,
48               ecx: &mut ExtCtxt,
49               span: Span,
50               token_tree: &[ast::TokenTree])
51               -> MacResult;
52 }
53
54 pub type MacroExpanderFn =
55     fn(ecx: &mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree])
56        -> MacResult;
57
58 impl MacroExpander for BasicMacroExpander {
59     fn expand(&self,
60               ecx: &mut ExtCtxt,
61               span: Span,
62               token_tree: &[ast::TokenTree])
63               -> MacResult {
64         (self.expander)(ecx, span, token_tree)
65     }
66 }
67
68 pub struct BasicIdentMacroExpander {
69     expander: IdentMacroExpanderFn,
70     span: Option<Span>
71 }
72
73 pub trait IdentMacroExpander {
74     fn expand(&self,
75               cx: &mut ExtCtxt,
76               sp: Span,
77               ident: ast::Ident,
78               token_tree: Vec<ast::TokenTree> )
79               -> MacResult;
80 }
81
82 impl IdentMacroExpander for BasicIdentMacroExpander {
83     fn expand(&self,
84               cx: &mut ExtCtxt,
85               sp: Span,
86               ident: ast::Ident,
87               token_tree: Vec<ast::TokenTree> )
88               -> MacResult {
89         (self.expander)(cx, sp, ident, token_tree)
90     }
91 }
92
93 pub type IdentMacroExpanderFn =
94     fn(&mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree> ) -> MacResult;
95
96 pub type MacroCrateRegistrationFun =
97     fn(|ast::Name, SyntaxExtension|);
98
99 pub trait AnyMacro {
100     fn make_expr(&self) -> @ast::Expr;
101     fn make_items(&self) -> SmallVector<@ast::Item>;
102     fn make_stmt(&self) -> @ast::Stmt;
103 }
104
105
106 pub enum MacResult {
107     MRExpr(@ast::Expr),
108     MRItem(@ast::Item),
109     MRAny(~AnyMacro:),
110     MRDef(MacroDef),
111 }
112 impl MacResult {
113     /// Create an empty expression MacResult; useful for satisfying
114     /// type signatures after emitting a non-fatal error (which stop
115     /// compilation well before the validity (or otherwise)) of the
116     /// expression are checked.
117     pub fn raw_dummy_expr(sp: codemap::Span) -> @ast::Expr {
118         @ast::Expr {
119             id: ast::DUMMY_NODE_ID,
120             node: ast::ExprLogLevel,
121             span: sp
122         }
123     }
124     pub fn dummy_expr(sp: codemap::Span) -> MacResult {
125         MRExpr(MacResult::raw_dummy_expr(sp))
126     }
127 }
128
129 pub enum SyntaxExtension {
130     // #[deriving] and such
131     ItemDecorator(ItemDecorator),
132
133     // Token-tree expanders
134     NormalTT(~MacroExpander:'static, Option<Span>),
135
136     // An IdentTT is a macro that has an
137     // identifier in between the name of the
138     // macro and the argument. Currently,
139     // the only examples of this is
140     // macro_rules!
141
142     // perhaps macro_rules! will lose its odd special identifier argument,
143     // and this can go away also
144     IdentTT(~IdentMacroExpander:'static, Option<Span>),
145 }
146
147 pub struct BlockInfo {
148     // should macros escape from this scope?
149     macros_escape : bool,
150     // what are the pending renames?
151     pending_renames : RenameList,
152 }
153
154 impl BlockInfo {
155     pub fn new() -> BlockInfo {
156         BlockInfo {
157             macros_escape: false,
158             pending_renames: Vec::new(),
159         }
160     }
161 }
162
163 // a list of ident->name renamings
164 pub type RenameList = Vec<(ast::Ident,Name)> ;
165
166 // The base map of methods for expanding syntax extension
167 // AST nodes into full ASTs
168 pub fn syntax_expander_table() -> SyntaxEnv {
169     // utility function to simplify creating NormalTT syntax extensions
170     fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
171         NormalTT(~BasicMacroExpander {
172                 expander: f,
173                 span: None,
174             },
175             None)
176     }
177
178     let mut syntax_expanders = SyntaxEnv::new();
179     syntax_expanders.insert(intern(&"macro_rules"),
180                             IdentTT(~BasicIdentMacroExpander {
181                                 expander: ext::tt::macro_rules::add_new_extension,
182                                 span: None,
183                             },
184                             None));
185     syntax_expanders.insert(intern(&"fmt"),
186                             builtin_normal_expander(
187                                 ext::fmt::expand_syntax_ext));
188     syntax_expanders.insert(intern(&"format_args"),
189                             builtin_normal_expander(
190                                 ext::format::expand_args));
191     syntax_expanders.insert(intern(&"env"),
192                             builtin_normal_expander(
193                                     ext::env::expand_env));
194     syntax_expanders.insert(intern(&"option_env"),
195                             builtin_normal_expander(
196                                     ext::env::expand_option_env));
197     syntax_expanders.insert(intern("bytes"),
198                             builtin_normal_expander(
199                                     ext::bytes::expand_syntax_ext));
200     syntax_expanders.insert(intern("concat_idents"),
201                             builtin_normal_expander(
202                                     ext::concat_idents::expand_syntax_ext));
203     syntax_expanders.insert(intern("concat"),
204                             builtin_normal_expander(
205                                     ext::concat::expand_syntax_ext));
206     syntax_expanders.insert(intern(&"log_syntax"),
207                             builtin_normal_expander(
208                                     ext::log_syntax::expand_syntax_ext));
209     syntax_expanders.insert(intern(&"deriving"),
210                             ItemDecorator(ext::deriving::expand_meta_deriving));
211
212     // Quasi-quoting expanders
213     syntax_expanders.insert(intern(&"quote_tokens"),
214                        builtin_normal_expander(
215                             ext::quote::expand_quote_tokens));
216     syntax_expanders.insert(intern(&"quote_expr"),
217                        builtin_normal_expander(
218                             ext::quote::expand_quote_expr));
219     syntax_expanders.insert(intern(&"quote_ty"),
220                        builtin_normal_expander(
221                             ext::quote::expand_quote_ty));
222     syntax_expanders.insert(intern(&"quote_item"),
223                        builtin_normal_expander(
224                             ext::quote::expand_quote_item));
225     syntax_expanders.insert(intern(&"quote_pat"),
226                        builtin_normal_expander(
227                             ext::quote::expand_quote_pat));
228     syntax_expanders.insert(intern(&"quote_stmt"),
229                        builtin_normal_expander(
230                             ext::quote::expand_quote_stmt));
231
232     syntax_expanders.insert(intern(&"line"),
233                             builtin_normal_expander(
234                                     ext::source_util::expand_line));
235     syntax_expanders.insert(intern(&"col"),
236                             builtin_normal_expander(
237                                     ext::source_util::expand_col));
238     syntax_expanders.insert(intern(&"file"),
239                             builtin_normal_expander(
240                                     ext::source_util::expand_file));
241     syntax_expanders.insert(intern(&"stringify"),
242                             builtin_normal_expander(
243                                     ext::source_util::expand_stringify));
244     syntax_expanders.insert(intern(&"include"),
245                             builtin_normal_expander(
246                                     ext::source_util::expand_include));
247     syntax_expanders.insert(intern(&"include_str"),
248                             builtin_normal_expander(
249                                     ext::source_util::expand_include_str));
250     syntax_expanders.insert(intern(&"include_bin"),
251                             builtin_normal_expander(
252                                     ext::source_util::expand_include_bin));
253     syntax_expanders.insert(intern(&"module_path"),
254                             builtin_normal_expander(
255                                     ext::source_util::expand_mod));
256     syntax_expanders.insert(intern(&"asm"),
257                             builtin_normal_expander(
258                                     ext::asm::expand_asm));
259     syntax_expanders.insert(intern(&"cfg"),
260                             builtin_normal_expander(
261                                     ext::cfg::expand_cfg));
262     syntax_expanders.insert(intern(&"trace_macros"),
263                             builtin_normal_expander(
264                                     ext::trace_macros::expand_trace_macros));
265     syntax_expanders
266 }
267
268 pub struct MacroCrate {
269     lib: Option<Path>,
270     cnum: ast::CrateNum,
271 }
272
273 pub trait CrateLoader {
274     fn load_crate(&mut self, krate: &ast::ViewItem) -> MacroCrate;
275     fn get_exported_macros(&mut self, crate_num: ast::CrateNum) -> Vec<~str> ;
276     fn get_registrar_symbol(&mut self, crate_num: ast::CrateNum) -> Option<~str>;
277 }
278
279 // One of these is made during expansion and incrementally updated as we go;
280 // when a macro expansion occurs, the resulting nodes have the backtrace()
281 // -> expn_info of their expansion context stored into their span.
282 pub struct ExtCtxt<'a> {
283     parse_sess: @parse::ParseSess,
284     cfg: ast::CrateConfig,
285     backtrace: Option<@ExpnInfo>,
286     loader: &'a mut CrateLoader,
287
288     mod_path: Vec<ast::Ident> ,
289     trace_mac: bool
290 }
291
292 impl<'a> ExtCtxt<'a> {
293     pub fn new<'a>(parse_sess: @parse::ParseSess, cfg: ast::CrateConfig,
294                loader: &'a mut CrateLoader) -> ExtCtxt<'a> {
295         ExtCtxt {
296             parse_sess: parse_sess,
297             cfg: cfg,
298             backtrace: None,
299             loader: loader,
300             mod_path: Vec::new(),
301             trace_mac: false
302         }
303     }
304
305     pub fn expand_expr(&mut self, mut e: @ast::Expr) -> @ast::Expr {
306         loop {
307             match e.node {
308                 ast::ExprMac(..) => {
309                     let mut expander = expand::MacroExpander {
310                         extsbox: syntax_expander_table(),
311                         cx: self,
312                     };
313                     e = expand::expand_expr(e, &mut expander);
314                 }
315                 _ => return e
316             }
317         }
318     }
319
320     pub fn codemap(&self) -> @CodeMap { self.parse_sess.cm }
321     pub fn parse_sess(&self) -> @parse::ParseSess { self.parse_sess }
322     pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
323     pub fn call_site(&self) -> Span {
324         match self.backtrace {
325             Some(expn_info) => expn_info.call_site,
326             None => self.bug("missing top span")
327         }
328     }
329     pub fn print_backtrace(&self) { }
330     pub fn backtrace(&self) -> Option<@ExpnInfo> { self.backtrace }
331     pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }
332     pub fn mod_pop(&mut self) { self.mod_path.pop().unwrap(); }
333     pub fn mod_path(&self) -> Vec<ast::Ident> { self.mod_path.clone() }
334     pub fn bt_push(&mut self, ei: codemap::ExpnInfo) {
335         match ei {
336             ExpnInfo {call_site: cs, callee: ref callee} => {
337                 self.backtrace =
338                     Some(@ExpnInfo {
339                         call_site: Span {lo: cs.lo, hi: cs.hi,
340                                          expn_info: self.backtrace},
341                         callee: (*callee).clone()
342                     });
343             }
344         }
345     }
346     pub fn bt_pop(&mut self) {
347         match self.backtrace {
348             Some(expn_info) => self.backtrace = expn_info.call_site.expn_info,
349             _ => self.bug("tried to pop without a push")
350         }
351     }
352     /// Emit `msg` attached to `sp`, and stop compilation immediately.
353     ///
354     /// `span_err` should be strongly prefered where-ever possible:
355     /// this should *only* be used when
356     /// - continuing has a high risk of flow-on errors (e.g. errors in
357     ///   declaring a macro would cause all uses of that macro to
358     ///   complain about "undefined macro"), or
359     /// - there is literally nothing else that can be done (however,
360     ///   in most cases one can construct a dummy expression/item to
361     ///   substitute; we never hit resolve/type-checking so the dummy
362     ///   value doesn't have to match anything)
363     pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
364         self.print_backtrace();
365         self.parse_sess.span_diagnostic.span_fatal(sp, msg);
366     }
367
368     /// Emit `msg` attached to `sp`, without immediately stopping
369     /// compilation.
370     ///
371     /// Compilation will be stopped in the near future (at the end of
372     /// the macro expansion phase).
373     pub fn span_err(&self, sp: Span, msg: &str) {
374         self.print_backtrace();
375         self.parse_sess.span_diagnostic.span_err(sp, msg);
376     }
377     pub fn span_warn(&self, sp: Span, msg: &str) {
378         self.print_backtrace();
379         self.parse_sess.span_diagnostic.span_warn(sp, msg);
380     }
381     pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
382         self.print_backtrace();
383         self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
384     }
385     pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
386         self.print_backtrace();
387         self.parse_sess.span_diagnostic.span_bug(sp, msg);
388     }
389     pub fn span_note(&self, sp: Span, msg: &str) {
390         self.print_backtrace();
391         self.parse_sess.span_diagnostic.span_note(sp, msg);
392     }
393     pub fn bug(&self, msg: &str) -> ! {
394         self.print_backtrace();
395         self.parse_sess.span_diagnostic.handler().bug(msg);
396     }
397     pub fn trace_macros(&self) -> bool {
398         self.trace_mac
399     }
400     pub fn set_trace_macros(&mut self, x: bool) {
401         self.trace_mac = x
402     }
403     pub fn ident_of(&self, st: &str) -> ast::Ident {
404         str_to_ident(st)
405     }
406 }
407
408 /// Extract a string literal from `expr`, emitting `err_msg` if `expr`
409 /// is not a string literal. This does not stop compilation on error,
410 /// merely emits a non-fatal error and returns None.
411 pub fn expr_to_str(cx: &ExtCtxt, expr: @ast::Expr, err_msg: &str)
412                    -> Option<(InternedString, ast::StrStyle)> {
413     match expr.node {
414         ast::ExprLit(l) => match l.node {
415             ast::LitStr(ref s, style) => return Some(((*s).clone(), style)),
416             _ => cx.span_err(l.span, err_msg)
417         },
418         _ => cx.span_err(expr.span, err_msg)
419     }
420     None
421 }
422
423 /// Non-fatally assert that `tts` is empty. Note that this function
424 /// returns even when `tts` is non-empty, macros that *need* to stop
425 /// compilation should call
426 /// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be
427 /// done as rarely as possible).
428 pub fn check_zero_tts(cx: &ExtCtxt,
429                       sp: Span,
430                       tts: &[ast::TokenTree],
431                       name: &str) {
432     if tts.len() != 0 {
433         cx.span_err(sp, format!("{} takes no arguments", name));
434     }
435 }
436
437 /// Extract the string literal from the first token of `tts`. If this
438 /// is not a string literal, emit an error and return None.
439 pub fn get_single_str_from_tts(cx: &ExtCtxt,
440                                sp: Span,
441                                tts: &[ast::TokenTree],
442                                name: &str)
443                                -> Option<~str> {
444     if tts.len() != 1 {
445         cx.span_err(sp, format!("{} takes 1 argument.", name));
446     } else {
447         match tts[0] {
448             ast::TTTok(_, token::LIT_STR(ident))
449             | ast::TTTok(_, token::LIT_STR_RAW(ident, _)) => {
450                 return Some(token::get_ident(ident).get().to_str())
451             }
452             _ => cx.span_err(sp, format!("{} requires a string.", name)),
453         }
454     }
455     None
456 }
457
458 /// Extract comma-separated expressions from `tts`. If there is a
459 /// parsing error, emit a non-fatal error and return None.
460 pub fn get_exprs_from_tts(cx: &ExtCtxt,
461                           sp: Span,
462                           tts: &[ast::TokenTree]) -> Option<Vec<@ast::Expr> > {
463     let mut p = parse::new_parser_from_tts(cx.parse_sess(),
464                                            cx.cfg(),
465                                            tts.iter()
466                                               .map(|x| (*x).clone())
467                                               .collect());
468     let mut es = Vec::new();
469     while p.token != token::EOF {
470         if es.len() != 0 && !p.eat(&token::COMMA) {
471             cx.span_err(sp, "expected token: `,`");
472             return None;
473         }
474         es.push(p.parse_expr());
475     }
476     Some(es)
477 }
478
479 // in order to have some notion of scoping for macros,
480 // we want to implement the notion of a transformation
481 // environment.
482
483 // This environment maps Names to SyntaxExtensions.
484
485 // Actually, the following implementation is parameterized
486 // by both key and value types.
487
488 //impl question: how to implement it? Initially, the
489 // env will contain only macros, so it might be painful
490 // to add an empty frame for every context. Let's just
491 // get it working, first....
492
493 // NB! the mutability of the underlying maps means that
494 // if expansion is out-of-order, a deeper scope may be
495 // able to refer to a macro that was added to an enclosing
496 // scope lexically later than the deeper scope.
497
498 struct MapChainFrame {
499     info: BlockInfo,
500     map: HashMap<Name, SyntaxExtension>,
501 }
502
503 #[unsafe_destructor]
504 impl Drop for MapChainFrame {
505     fn drop(&mut self) {
506         // make sure that syntax extension dtors run before we drop the libs
507         self.map.clear();
508     }
509 }
510
511 // Only generic to make it easy to test
512 pub struct SyntaxEnv {
513     priv chain: Vec<MapChainFrame> ,
514 }
515
516 impl SyntaxEnv {
517     pub fn new() -> SyntaxEnv {
518         let mut map = SyntaxEnv { chain: Vec::new() };
519         map.push_frame();
520         map
521     }
522
523     pub fn push_frame(&mut self) {
524         self.chain.push(MapChainFrame {
525             info: BlockInfo::new(),
526             map: HashMap::new(),
527         });
528     }
529
530     pub fn pop_frame(&mut self) {
531         assert!(self.chain.len() > 1, "too many pops on MapChain!");
532         self.chain.pop();
533     }
534
535     fn find_escape_frame<'a>(&'a mut self) -> &'a mut MapChainFrame {
536         for (i, frame) in self.chain.mut_iter().enumerate().rev() {
537             if !frame.info.macros_escape || i == 0 {
538                 return frame
539             }
540         }
541         unreachable!()
542     }
543
544     pub fn find<'a>(&'a self, k: &Name) -> Option<&'a SyntaxExtension> {
545         for frame in self.chain.iter().rev() {
546             match frame.map.find(k) {
547                 Some(v) => return Some(v),
548                 None => {}
549             }
550         }
551         None
552     }
553
554     pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
555         self.find_escape_frame().map.insert(k, v);
556     }
557
558     pub fn info<'a>(&'a mut self) -> &'a mut BlockInfo {
559         let last_chain_index = self.chain.len() - 1;
560         &mut self.chain.get_mut(last_chain_index).info
561     }
562 }