]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/base.rs
Remove 'Local Variable' comments
[rust.git] / src / libsyntax / ext / base.rs
1 // Copyright 2012-2013 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 codemap;
13 use codemap::{CodeMap, span, ExpnInfo, ExpandedFrom};
14 use codemap::CallInfo;
15 use diagnostic::span_handler;
16 use ext;
17 use parse;
18 use parse::token;
19
20 use core::hashmap::HashMap;
21
22 // new-style macro! tt code:
23 //
24 //    SyntaxExpanderTT, SyntaxExpanderTTItem, MacResult,
25 //    NormalTT, IdentTT
26 //
27 // also note that ast::mac used to have a bunch of extraneous cases and
28 // is now probably a redundant AST node, can be merged with
29 // ast::mac_invoc_tt.
30
31 pub struct MacroDef {
32     name: ~str,
33     ext: SyntaxExtension
34 }
35
36 pub type ItemDecorator = @fn(@ext_ctxt,
37                              span,
38                              @ast::meta_item,
39                              ~[@ast::item])
40                           -> ~[@ast::item];
41
42 pub struct SyntaxExpanderTT {
43     expander: SyntaxExpanderTTFun,
44     span: Option<span>
45 }
46
47 pub type SyntaxExpanderTTFun = @fn(@ext_ctxt,
48                                    span,
49                                    &[ast::token_tree])
50                                 -> MacResult;
51
52 pub struct SyntaxExpanderTTItem {
53     expander: SyntaxExpanderTTItemFun,
54     span: Option<span>
55 }
56
57 pub type SyntaxExpanderTTItemFun = @fn(@ext_ctxt,
58                                        span,
59                                        ast::ident,
60                                        ~[ast::token_tree])
61                                     -> MacResult;
62
63 pub enum MacResult {
64     MRExpr(@ast::expr),
65     MRItem(@ast::item),
66     MRAny(@fn() -> @ast::expr,
67           @fn() -> Option<@ast::item>,
68           @fn() -> @ast::stmt),
69     MRDef(MacroDef)
70 }
71
72 pub enum SyntaxExtension {
73
74     // #[auto_encode] and such
75     ItemDecorator(ItemDecorator),
76
77     // Token-tree expanders
78     NormalTT(SyntaxExpanderTT),
79
80     // An IdentTT is a macro that has an
81     // identifier in between the name of the
82     // macro and the argument. Currently,
83     // the only examples of this are
84     // macro_rules! and proto!
85
86     // perhaps macro_rules! will lose its odd special identifier argument,
87     // and this can go away also
88     IdentTT(SyntaxExpanderTTItem),
89 }
90
91 pub type SyntaxEnv = @mut MapChain<Name, Transformer>;
92
93 // Name : the domain of SyntaxEnvs
94 // want to change these to uints....
95 // note that we use certain strings that are not legal as identifiers
96 // to indicate, for instance, how blocks are supposed to behave.
97 type Name = @~str;
98
99 // Transformer : the codomain of SyntaxEnvs
100
101 // NB: it may seem crazy to lump both of these into one environment;
102 // what would it mean to bind "foo" to BlockLimit(true)? The idea
103 // is that this follows the lead of MTWT, and accommodates growth
104 // toward a more uniform syntax syntax (sorry) where blocks are just
105 // another kind of transformer.
106
107 pub enum Transformer {
108     // this identifier maps to a syntax extension or macro
109     SE(SyntaxExtension),
110     // should blocks occurring here limit macro scopes?
111     ScopeMacros(bool)
112 }
113
114 // The base map of methods for expanding syntax extension
115 // AST nodes into full ASTs
116 pub fn syntax_expander_table() -> SyntaxEnv {
117     // utility function to simplify creating NormalTT syntax extensions
118     fn builtin_normal_tt(f: SyntaxExpanderTTFun) -> @Transformer {
119         @SE(NormalTT(SyntaxExpanderTT{expander: f, span: None}))
120     }
121     // utility function to simplify creating IdentTT syntax extensions
122     fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer {
123         @SE(IdentTT(SyntaxExpanderTTItem{expander: f, span: None}))
124     }
125     let mut syntax_expanders = HashMap::new();
126     // NB identifier starts with space, and can't conflict with legal idents
127     syntax_expanders.insert(@~" block",
128                             @ScopeMacros(true));
129     syntax_expanders.insert(@~"macro_rules",
130                             builtin_item_tt(
131                                 ext::tt::macro_rules::add_new_extension));
132     syntax_expanders.insert(@~"fmt",
133                             builtin_normal_tt(ext::fmt::expand_syntax_ext));
134     syntax_expanders.insert(
135         @~"auto_encode",
136         @SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
137     syntax_expanders.insert(
138         @~"auto_decode",
139         @SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
140     syntax_expanders.insert(@~"env",
141                             builtin_normal_tt(ext::env::expand_syntax_ext));
142     syntax_expanders.insert(@~"concat_idents",
143                             builtin_normal_tt(
144                                 ext::concat_idents::expand_syntax_ext));
145     syntax_expanders.insert(@~"log_syntax",
146                             builtin_normal_tt(
147                                 ext::log_syntax::expand_syntax_ext));
148     syntax_expanders.insert(@~"deriving",
149                             @SE(ItemDecorator(
150                                 ext::deriving::expand_meta_deriving)));
151     syntax_expanders.insert(@~"deriving_eq",
152                             @SE(ItemDecorator(
153                                 ext::deriving::eq::expand_deriving_obsolete)));
154     syntax_expanders.insert(@~"deriving_iter_bytes",
155                             @SE(ItemDecorator(
156                                 ext::deriving::iter_bytes::expand_deriving_obsolete)));
157     syntax_expanders.insert(@~"deriving_clone",
158                             @SE(ItemDecorator(
159                                 ext::deriving::clone::expand_deriving_obsolete)));
160
161     // Quasi-quoting expanders
162     syntax_expanders.insert(@~"quote_tokens",
163                        builtin_normal_tt(ext::quote::expand_quote_tokens));
164     syntax_expanders.insert(@~"quote_expr",
165                        builtin_normal_tt(ext::quote::expand_quote_expr));
166     syntax_expanders.insert(@~"quote_ty",
167                        builtin_normal_tt(ext::quote::expand_quote_ty));
168     syntax_expanders.insert(@~"quote_item",
169                        builtin_normal_tt(ext::quote::expand_quote_item));
170     syntax_expanders.insert(@~"quote_pat",
171                        builtin_normal_tt(ext::quote::expand_quote_pat));
172     syntax_expanders.insert(@~"quote_stmt",
173                        builtin_normal_tt(ext::quote::expand_quote_stmt));
174
175     syntax_expanders.insert(@~"line",
176                             builtin_normal_tt(
177                                 ext::source_util::expand_line));
178     syntax_expanders.insert(@~"col",
179                             builtin_normal_tt(
180                                 ext::source_util::expand_col));
181     syntax_expanders.insert(@~"file",
182                             builtin_normal_tt(
183                                 ext::source_util::expand_file));
184     syntax_expanders.insert(@~"stringify",
185                             builtin_normal_tt(
186                                 ext::source_util::expand_stringify));
187     syntax_expanders.insert(@~"include",
188                             builtin_normal_tt(
189                                 ext::source_util::expand_include));
190     syntax_expanders.insert(@~"include_str",
191                             builtin_normal_tt(
192                                 ext::source_util::expand_include_str));
193     syntax_expanders.insert(@~"include_bin",
194                             builtin_normal_tt(
195                                 ext::source_util::expand_include_bin));
196     syntax_expanders.insert(@~"module_path",
197                             builtin_normal_tt(
198                                 ext::source_util::expand_mod));
199     syntax_expanders.insert(@~"proto",
200                             builtin_item_tt(ext::pipes::expand_proto));
201     syntax_expanders.insert(@~"asm",
202                             builtin_normal_tt(ext::asm::expand_asm));
203     syntax_expanders.insert(
204         @~"trace_macros",
205         builtin_normal_tt(ext::trace_macros::expand_trace_macros));
206     MapChain::new(~syntax_expanders)
207 }
208
209 // One of these is made during expansion and incrementally updated as we go;
210 // when a macro expansion occurs, the resulting nodes have the backtrace()
211 // -> expn_info of their expansion context stored into their span.
212 pub trait ext_ctxt {
213     fn codemap(@mut self) -> @CodeMap;
214     fn parse_sess(@mut self) -> @mut parse::ParseSess;
215     fn cfg(@mut self) -> ast::crate_cfg;
216     fn call_site(@mut self) -> span;
217     fn print_backtrace(@mut self);
218     fn backtrace(@mut self) -> Option<@ExpnInfo>;
219     fn mod_push(@mut self, mod_name: ast::ident);
220     fn mod_pop(@mut self);
221     fn mod_path(@mut self) -> ~[ast::ident];
222     fn bt_push(@mut self, ei: codemap::ExpnInfo);
223     fn bt_pop(@mut self);
224     fn span_fatal(@mut self, sp: span, msg: &str) -> !;
225     fn span_err(@mut self, sp: span, msg: &str);
226     fn span_warn(@mut self, sp: span, msg: &str);
227     fn span_unimpl(@mut self, sp: span, msg: &str) -> !;
228     fn span_bug(@mut self, sp: span, msg: &str) -> !;
229     fn bug(@mut self, msg: &str) -> !;
230     fn next_id(@mut self) -> ast::node_id;
231     fn trace_macros(@mut self) -> bool;
232     fn set_trace_macros(@mut self, x: bool);
233     /* for unhygienic identifier transformation */
234     fn str_of(@mut self, id: ast::ident) -> ~str;
235     fn ident_of(@mut self, st: ~str) -> ast::ident;
236 }
237
238 pub fn mk_ctxt(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg)
239             -> @ext_ctxt {
240     struct CtxtRepr {
241         parse_sess: @mut parse::ParseSess,
242         cfg: ast::crate_cfg,
243         backtrace: @mut Option<@ExpnInfo>,
244         mod_path: ~[ast::ident],
245         trace_mac: bool
246     }
247     impl ext_ctxt for CtxtRepr {
248         fn codemap(@mut self) -> @CodeMap { self.parse_sess.cm }
249         fn parse_sess(@mut self) -> @mut parse::ParseSess { self.parse_sess }
250         fn cfg(@mut self) -> ast::crate_cfg { copy self.cfg }
251         fn call_site(@mut self) -> span {
252             match *self.backtrace {
253                 Some(@ExpandedFrom(CallInfo {call_site: cs, _})) => cs,
254                 None => self.bug(~"missing top span")
255             }
256         }
257         fn print_backtrace(@mut self) { }
258         fn backtrace(@mut self) -> Option<@ExpnInfo> { *self.backtrace }
259         fn mod_push(@mut self, i: ast::ident) { self.mod_path.push(i); }
260         fn mod_pop(@mut self) { self.mod_path.pop(); }
261         fn mod_path(@mut self) -> ~[ast::ident] { copy self.mod_path }
262         fn bt_push(@mut self, ei: codemap::ExpnInfo) {
263             match ei {
264               ExpandedFrom(CallInfo {call_site: cs, callee: ref callee}) => {
265                 *self.backtrace =
266                     Some(@ExpandedFrom(CallInfo {
267                         call_site: span {lo: cs.lo, hi: cs.hi,
268                                          expn_info: *self.backtrace},
269                         callee: copy *callee}));
270               }
271             }
272         }
273         fn bt_pop(@mut self) {
274             match *self.backtrace {
275               Some(@ExpandedFrom(CallInfo {
276                   call_site: span {expn_info: prev, _}, _
277               })) => {
278                 *self.backtrace = prev
279               }
280               _ => self.bug(~"tried to pop without a push")
281             }
282         }
283         fn span_fatal(@mut self, sp: span, msg: &str) -> ! {
284             self.print_backtrace();
285             self.parse_sess.span_diagnostic.span_fatal(sp, msg);
286         }
287         fn span_err(@mut self, sp: span, msg: &str) {
288             self.print_backtrace();
289             self.parse_sess.span_diagnostic.span_err(sp, msg);
290         }
291         fn span_warn(@mut self, sp: span, msg: &str) {
292             self.print_backtrace();
293             self.parse_sess.span_diagnostic.span_warn(sp, msg);
294         }
295         fn span_unimpl(@mut self, sp: span, msg: &str) -> ! {
296             self.print_backtrace();
297             self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
298         }
299         fn span_bug(@mut self, sp: span, msg: &str) -> ! {
300             self.print_backtrace();
301             self.parse_sess.span_diagnostic.span_bug(sp, msg);
302         }
303         fn bug(@mut self, msg: &str) -> ! {
304             self.print_backtrace();
305             self.parse_sess.span_diagnostic.handler().bug(msg);
306         }
307         fn next_id(@mut self) -> ast::node_id {
308             return parse::next_node_id(self.parse_sess);
309         }
310         fn trace_macros(@mut self) -> bool {
311             self.trace_mac
312         }
313         fn set_trace_macros(@mut self, x: bool) {
314             self.trace_mac = x
315         }
316         fn str_of(@mut self, id: ast::ident) -> ~str {
317             copy *self.parse_sess.interner.get(id)
318         }
319         fn ident_of(@mut self, st: ~str) -> ast::ident {
320             self.parse_sess.interner.intern(@/*bad*/ copy st)
321         }
322     }
323     let imp: @mut CtxtRepr = @mut CtxtRepr {
324         parse_sess: parse_sess,
325         cfg: cfg,
326         backtrace: @mut None,
327         mod_path: ~[],
328         trace_mac: false
329     };
330     ((imp) as @ext_ctxt)
331 }
332
333 pub fn expr_to_str(cx: @ext_ctxt, expr: @ast::expr, err_msg: ~str) -> ~str {
334     match expr.node {
335       ast::expr_lit(l) => match l.node {
336         ast::lit_str(s) => copy *s,
337         _ => cx.span_fatal(l.span, err_msg)
338       },
339       _ => cx.span_fatal(expr.span, err_msg)
340     }
341 }
342
343 pub fn expr_to_ident(cx: @ext_ctxt,
344                      expr: @ast::expr,
345                      err_msg: ~str) -> ast::ident {
346     match expr.node {
347       ast::expr_path(p) => {
348         if vec::len(p.types) > 0u || vec::len(p.idents) != 1u {
349             cx.span_fatal(expr.span, err_msg);
350         }
351         return p.idents[0];
352       }
353       _ => cx.span_fatal(expr.span, err_msg)
354     }
355 }
356
357 pub fn check_zero_tts(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree],
358                       name: &str) {
359     if tts.len() != 0 {
360         cx.span_fatal(sp, fmt!("%s takes no arguments", name));
361     }
362 }
363
364 pub fn get_single_str_from_tts(cx: @ext_ctxt,
365                                sp: span,
366                                tts: &[ast::token_tree],
367                                name: &str) -> ~str {
368     if tts.len() != 1 {
369         cx.span_fatal(sp, fmt!("%s takes 1 argument.", name));
370     }
371
372     match tts[0] {
373         ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident),
374         _ =>
375         cx.span_fatal(sp, fmt!("%s requires a string.", name))
376     }
377 }
378
379 pub fn get_exprs_from_tts(cx: @ext_ctxt, tts: &[ast::token_tree])
380                        -> ~[@ast::expr] {
381     let p = parse::new_parser_from_tts(cx.parse_sess(),
382                                        cx.cfg(),
383                                        vec::from_slice(tts));
384     let mut es = ~[];
385     while *p.token != token::EOF {
386         if es.len() != 0 {
387             p.eat(&token::COMMA);
388         }
389         es.push(p.parse_expr());
390     }
391     es
392 }
393
394 // in order to have some notion of scoping for macros,
395 // we want to implement the notion of a transformation
396 // environment.
397
398 // This environment maps Names to Transformers.
399 // Initially, this includes macro definitions and
400 // block directives.
401
402
403
404 // Actually, the following implementation is parameterized
405 // by both key and value types.
406
407 //impl question: how to implement it? Initially, the
408 // env will contain only macros, so it might be painful
409 // to add an empty frame for every context. Let's just
410 // get it working, first....
411
412 // NB! the mutability of the underlying maps means that
413 // if expansion is out-of-order, a deeper scope may be
414 // able to refer to a macro that was added to an enclosing
415 // scope lexically later than the deeper scope.
416
417 // Note on choice of representation: I've been pushed to
418 // use a top-level managed pointer by some difficulties
419 // with pushing and popping functionally, and the ownership
420 // issues.  As a result, the values returned by the table
421 // also need to be managed; the &'self ... type that Maps
422 // return won't work for things that need to get outside
423 // of that managed pointer.  The easiest way to do this
424 // is just to insist that the values in the tables are
425 // managed to begin with.
426
427 // a transformer env is either a base map or a map on top
428 // of another chain.
429 pub enum MapChain<K,V> {
430     BaseMapChain(~HashMap<K,@V>),
431     ConsMapChain(~HashMap<K,@V>,@mut MapChain<K,V>)
432 }
433
434
435 // get the map from an env frame
436 impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{
437
438     // Constructor. I don't think we need a zero-arg one.
439     fn new(init: ~HashMap<K,@V>) -> @mut MapChain<K,V> {
440         @mut BaseMapChain(init)
441     }
442
443     // add a new frame to the environment (functionally)
444     fn push_frame (@mut self) -> @mut MapChain<K,V> {
445         @mut ConsMapChain(~HashMap::new() ,self)
446     }
447
448 // no need for pop, it'll just be functional.
449
450     // utility fn...
451
452     // ugh: can't get this to compile with mut because of the
453     // lack of flow sensitivity.
454     #[cfg(stage0)]
455     fn get_map(&self) -> &'self HashMap<K,@V> {
456         match *self {
457             BaseMapChain (~ref map) => map,
458             ConsMapChain (~ref map,_) => map
459         }
460     }
461
462     // ugh: can't get this to compile with mut because of the
463     // lack of flow sensitivity.
464     #[cfg(not(stage0))]
465     fn get_map<'a>(&'a self) -> &'a HashMap<K,@V> {
466         match *self {
467             BaseMapChain (~ref map) => map,
468             ConsMapChain (~ref map,_) => map
469         }
470     }
471
472 // traits just don't work anywhere...?
473 //pub impl Map<Name,SyntaxExtension> for MapChain {
474
475     fn contains_key (&self, key: &K) -> bool {
476         match *self {
477             BaseMapChain (ref map) => map.contains_key(key),
478             ConsMapChain (ref map,ref rest) =>
479             (map.contains_key(key)
480              || rest.contains_key(key))
481         }
482     }
483     // should each_key and each_value operate on shadowed
484     // names? I think not.
485     // delaying implementing this....
486     fn each_key (&self, _f: &fn (&K)->bool) {
487         fail!(~"unimplemented 2013-02-15T10:01");
488     }
489
490     fn each_value (&self, _f: &fn (&V) -> bool) {
491         fail!(~"unimplemented 2013-02-15T10:02");
492     }
493
494     // Returns a copy of the value that the name maps to.
495     // Goes down the chain 'til it finds one (or bottom out).
496     fn find (&self, key: &K) -> Option<@V> {
497         match self.get_map().find (key) {
498             Some(ref v) => Some(**v),
499             None => match *self {
500                 BaseMapChain (_) => None,
501                 ConsMapChain (_,ref rest) => rest.find(key)
502             }
503         }
504     }
505
506     // insert the binding into the top-level map
507     fn insert (&mut self, key: K, ext: @V) -> bool {
508         // can't abstract over get_map because of flow sensitivity...
509         match *self {
510             BaseMapChain (~ref mut map) => map.insert(key, ext),
511             ConsMapChain (~ref mut map,_) => map.insert(key,ext)
512         }
513     }
514
515 }
516
517 #[cfg(test)]
518 mod test {
519     use super::MapChain;
520     use core::hashmap::HashMap;
521
522     #[test] fn testenv () {
523         let mut a = HashMap::new();
524         a.insert (@~"abc",@15);
525         let m = MapChain::new(~a);
526         m.insert (@~"def",@16);
527         // FIXME: #4492 (ICE)  assert_eq!(m.find(&@~"abc"),Some(@15));
528         //  ....               assert_eq!(m.find(&@~"def"),Some(@16));
529         assert_eq!(*(m.find(&@~"abc").get()),15);
530         assert_eq!(*(m.find(&@~"def").get()),16);
531         let n = m.push_frame();
532         // old bindings are still present:
533         assert_eq!(*(n.find(&@~"abc").get()),15);
534         assert_eq!(*(n.find(&@~"def").get()),16);
535         n.insert (@~"def",@17);
536         // n shows the new binding
537         assert_eq!(*(n.find(&@~"abc").get()),15);
538         assert_eq!(*(n.find(&@~"def").get()),17);
539         // ... but m still has the old ones
540         // FIXME: #4492: assert_eq!(m.find(&@~"abc"),Some(@15));
541         // FIXME: #4492: assert_eq!(m.find(&@~"def"),Some(@16));
542         assert_eq!(*(m.find(&@~"abc").get()),15);
543         assert_eq!(*(m.find(&@~"def").get()),16);
544     }
545 }