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.
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};
15 use diagnostic::span_handler;
19 use parse::token::{ident_to_str, intern, str_to_ident};
21 use std::hashmap::HashMap;
23 // new-style macro! tt code:
25 // SyntaxExpanderTT, SyntaxExpanderTTItem, MacResult,
28 // also note that ast::mac used to have a bunch of extraneous cases and
29 // is now probably a redundant AST node, can be merged with
37 pub type ItemDecorator = @fn(@ExtCtxt,
43 pub struct SyntaxExpanderTT {
44 expander: SyntaxExpanderTTFun,
48 pub type SyntaxExpanderTTFun = @fn(@ExtCtxt,
53 pub struct SyntaxExpanderTTItem {
54 expander: SyntaxExpanderTTItemFun,
58 pub type SyntaxExpanderTTItemFun = @fn(@ExtCtxt,
67 MRAny(@fn() -> @ast::expr,
68 @fn() -> Option<@ast::item>,
73 pub enum SyntaxExtension {
75 // #[auto_encode] and such
76 ItemDecorator(ItemDecorator),
78 // Token-tree expanders
79 NormalTT(SyntaxExpanderTT),
81 // An IdentTT is a macro that has an
82 // identifier in between the name of the
83 // macro and the argument. Currently,
84 // the only examples of this is
87 // perhaps macro_rules! will lose its odd special identifier argument,
88 // and this can go away also
89 IdentTT(SyntaxExpanderTTItem),
92 // The SyntaxEnv is the environment that's threaded through the expansion
93 // of macros. It contains bindings for macros, and also a special binding
94 // for " block" (not a legal identifier) that maps to a BlockInfo
95 pub type SyntaxEnv = @mut MapChain<Name, Transformer>;
97 // Transformer : the codomain of SyntaxEnvs
99 pub enum Transformer {
100 // this identifier maps to a syntax extension or macro
102 // blockinfo : this is ... well, it's simpler than threading
103 // another whole data stack-structured data structure through
104 // expansion. Basically, there's an invariant that every
105 // map must contain a binding for " block".
109 pub struct BlockInfo {
110 // should macros escape from this scope?
111 macros_escape : bool,
112 // what are the pending renames?
113 pending_renames : @mut RenameList
116 // a list of ident->name renamings
117 type RenameList = ~[(ast::ident,Name)];
119 // The base map of methods for expanding syntax extension
120 // AST nodes into full ASTs
121 pub fn syntax_expander_table() -> SyntaxEnv {
122 // utility function to simplify creating NormalTT syntax extensions
123 fn builtin_normal_tt(f: SyntaxExpanderTTFun) -> @Transformer {
124 @SE(NormalTT(SyntaxExpanderTT{expander: f, span: None}))
126 // utility function to simplify creating IdentTT syntax extensions
127 fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer {
128 @SE(IdentTT(SyntaxExpanderTTItem{expander: f, span: None}))
130 let mut syntax_expanders = HashMap::new();
131 // NB identifier starts with space, and can't conflict with legal idents
132 syntax_expanders.insert(intern(&" block"),
133 @BlockInfo(BlockInfo{
134 macros_escape : false,
135 pending_renames : @mut ~[]
137 syntax_expanders.insert(intern(&"macro_rules"),
139 ext::tt::macro_rules::add_new_extension));
140 syntax_expanders.insert(intern(&"fmt"),
141 builtin_normal_tt(ext::fmt::expand_syntax_ext));
142 syntax_expanders.insert(
143 intern(&"auto_encode"),
144 @SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
145 syntax_expanders.insert(
146 intern(&"auto_decode"),
147 @SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
148 syntax_expanders.insert(intern(&"env"),
149 builtin_normal_tt(ext::env::expand_syntax_ext));
150 syntax_expanders.insert(intern("bytes"),
151 builtin_normal_tt(ext::bytes::expand_syntax_ext));
152 syntax_expanders.insert(intern("concat_idents"),
154 ext::concat_idents::expand_syntax_ext));
155 syntax_expanders.insert(intern(&"log_syntax"),
157 ext::log_syntax::expand_syntax_ext));
158 syntax_expanders.insert(intern(&"deriving"),
160 ext::deriving::expand_meta_deriving)));
162 // Quasi-quoting expanders
163 syntax_expanders.insert(intern(&"quote_tokens"),
164 builtin_normal_tt(ext::quote::expand_quote_tokens));
165 syntax_expanders.insert(intern(&"quote_expr"),
166 builtin_normal_tt(ext::quote::expand_quote_expr));
167 syntax_expanders.insert(intern(&"quote_ty"),
168 builtin_normal_tt(ext::quote::expand_quote_ty));
169 syntax_expanders.insert(intern(&"quote_item"),
170 builtin_normal_tt(ext::quote::expand_quote_item));
171 syntax_expanders.insert(intern(&"quote_pat"),
172 builtin_normal_tt(ext::quote::expand_quote_pat));
173 syntax_expanders.insert(intern(&"quote_stmt"),
174 builtin_normal_tt(ext::quote::expand_quote_stmt));
176 syntax_expanders.insert(intern(&"line"),
178 ext::source_util::expand_line));
179 syntax_expanders.insert(intern(&"col"),
181 ext::source_util::expand_col));
182 syntax_expanders.insert(intern(&"file"),
184 ext::source_util::expand_file));
185 syntax_expanders.insert(intern(&"stringify"),
187 ext::source_util::expand_stringify));
188 syntax_expanders.insert(intern(&"include"),
190 ext::source_util::expand_include));
191 syntax_expanders.insert(intern(&"include_str"),
193 ext::source_util::expand_include_str));
194 syntax_expanders.insert(intern(&"include_bin"),
196 ext::source_util::expand_include_bin));
197 syntax_expanders.insert(intern(&"module_path"),
199 ext::source_util::expand_mod));
200 syntax_expanders.insert(intern(&"asm"),
201 builtin_normal_tt(ext::asm::expand_asm));
202 syntax_expanders.insert(intern(&"cfg"),
203 builtin_normal_tt(ext::cfg::expand_cfg));
204 syntax_expanders.insert(
205 intern(&"trace_macros"),
206 builtin_normal_tt(ext::trace_macros::expand_trace_macros));
207 MapChain::new(~syntax_expanders)
210 // One of these is made during expansion and incrementally updated as we go;
211 // when a macro expansion occurs, the resulting nodes have the backtrace()
212 // -> expn_info of their expansion context stored into their span.
214 parse_sess: @mut parse::ParseSess,
215 cfg: ast::CrateConfig,
216 backtrace: @mut Option<@ExpnInfo>,
218 // These two @mut's should really not be here,
219 // but the self types for CtxtRepr are all wrong
220 // and there are bugs in the code for object
221 // types that make this hard to get right at the
222 // moment. - nmatsakis
223 mod_path: @mut ~[ast::ident],
228 pub fn new(parse_sess: @mut parse::ParseSess, cfg: ast::CrateConfig)
231 parse_sess: parse_sess,
233 backtrace: @mut None,
235 trace_mac: @mut false
239 pub fn codemap(&self) -> @CodeMap { self.parse_sess.cm }
240 pub fn parse_sess(&self) -> @mut parse::ParseSess { self.parse_sess }
241 pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
242 pub fn call_site(&self) -> span {
243 match *self.backtrace {
244 Some(@ExpnInfo {call_site: cs, _}) => cs,
245 None => self.bug("missing top span")
248 pub fn print_backtrace(&self) { }
249 pub fn backtrace(&self) -> Option<@ExpnInfo> { *self.backtrace }
250 pub fn mod_push(&self, i: ast::ident) { self.mod_path.push(i); }
251 pub fn mod_pop(&self) { self.mod_path.pop(); }
252 pub fn mod_path(&self) -> ~[ast::ident] { (*self.mod_path).clone() }
253 pub fn bt_push(&self, ei: codemap::ExpnInfo) {
255 ExpnInfo {call_site: cs, callee: ref callee} => {
258 call_site: span {lo: cs.lo, hi: cs.hi,
259 expn_info: *self.backtrace},
264 pub fn bt_pop(&self) {
265 match *self.backtrace {
267 call_site: span {expn_info: prev, _}, _}) => {
268 *self.backtrace = prev
270 _ => self.bug("tried to pop without a push")
273 pub fn span_fatal(&self, sp: span, msg: &str) -> ! {
274 self.print_backtrace();
275 self.parse_sess.span_diagnostic.span_fatal(sp, msg);
277 pub fn span_err(&self, sp: span, msg: &str) {
278 self.print_backtrace();
279 self.parse_sess.span_diagnostic.span_err(sp, msg);
281 pub fn span_warn(&self, sp: span, msg: &str) {
282 self.print_backtrace();
283 self.parse_sess.span_diagnostic.span_warn(sp, msg);
285 pub fn span_unimpl(&self, sp: span, msg: &str) -> ! {
286 self.print_backtrace();
287 self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
289 pub fn span_bug(&self, sp: span, msg: &str) -> ! {
290 self.print_backtrace();
291 self.parse_sess.span_diagnostic.span_bug(sp, msg);
293 pub fn bug(&self, msg: &str) -> ! {
294 self.print_backtrace();
295 self.parse_sess.span_diagnostic.handler().bug(msg);
297 pub fn next_id(&self) -> ast::NodeId {
298 parse::next_node_id(self.parse_sess)
300 pub fn trace_macros(&self) -> bool {
303 pub fn set_trace_macros(&self, x: bool) {
306 pub fn str_of(&self, id: ast::ident) -> @str {
309 pub fn ident_of(&self, st: &str) -> ast::ident {
314 pub fn expr_to_str(cx: @ExtCtxt, expr: @ast::expr, err_msg: ~str) -> @str {
316 ast::expr_lit(l) => match l.node {
317 ast::lit_str(s) => s,
318 _ => cx.span_fatal(l.span, err_msg)
320 _ => cx.span_fatal(expr.span, err_msg)
324 pub fn expr_to_ident(cx: @ExtCtxt,
326 err_msg: &str) -> ast::ident {
328 ast::expr_path(ref p) => {
329 if p.types.len() > 0u || p.idents.len() != 1u {
330 cx.span_fatal(expr.span, err_msg);
334 _ => cx.span_fatal(expr.span, err_msg)
338 pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
341 cx.span_fatal(sp, fmt!("%s takes no arguments", name));
345 pub fn get_single_str_from_tts(cx: @ExtCtxt,
347 tts: &[ast::token_tree],
348 name: &str) -> @str {
350 cx.span_fatal(sp, fmt!("%s takes 1 argument.", name));
354 ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident),
356 cx.span_fatal(sp, fmt!("%s requires a string.", name))
360 pub fn get_exprs_from_tts(cx: @ExtCtxt,
362 tts: &[ast::token_tree]) -> ~[@ast::expr] {
363 let p = parse::new_parser_from_tts(cx.parse_sess(),
367 while *p.token != token::EOF {
368 if es.len() != 0 && !p.eat(&token::COMMA) {
369 cx.span_fatal(sp, "expected token: `,`");
371 es.push(p.parse_expr());
376 // in order to have some notion of scoping for macros,
377 // we want to implement the notion of a transformation
380 // This environment maps Names to Transformers.
381 // Initially, this includes macro definitions and
386 // Actually, the following implementation is parameterized
387 // by both key and value types.
389 //impl question: how to implement it? Initially, the
390 // env will contain only macros, so it might be painful
391 // to add an empty frame for every context. Let's just
392 // get it working, first....
394 // NB! the mutability of the underlying maps means that
395 // if expansion is out-of-order, a deeper scope may be
396 // able to refer to a macro that was added to an enclosing
397 // scope lexically later than the deeper scope.
399 // Note on choice of representation: I've been pushed to
400 // use a top-level managed pointer by some difficulties
401 // with pushing and popping functionally, and the ownership
402 // issues. As a result, the values returned by the table
403 // also need to be managed; the &'self ... type that Maps
404 // return won't work for things that need to get outside
405 // of that managed pointer. The easiest way to do this
406 // is just to insist that the values in the tables are
407 // managed to begin with.
409 // a transformer env is either a base map or a map on top
411 pub enum MapChain<K,V> {
412 BaseMapChain(~HashMap<K,@V>),
413 ConsMapChain(~HashMap<K,@V>,@mut MapChain<K,V>)
417 // get the map from an env frame
418 impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{
419 // Constructor. I don't think we need a zero-arg one.
420 fn new(init: ~HashMap<K,@V>) -> @mut MapChain<K,V> {
421 @mut BaseMapChain(init)
424 // add a new frame to the environment (functionally)
425 fn push_frame (@mut self) -> @mut MapChain<K,V> {
426 @mut ConsMapChain(~HashMap::new() ,self)
429 // no need for pop, it'll just be functional.
433 // ugh: can't get this to compile with mut because of the
434 // lack of flow sensitivity.
435 fn get_map<'a>(&'a self) -> &'a HashMap<K,@V> {
437 BaseMapChain (~ref map) => map,
438 ConsMapChain (~ref map,_) => map
442 // traits just don't work anywhere...?
443 //impl Map<Name,SyntaxExtension> for MapChain {
445 fn contains_key (&self, key: &K) -> bool {
447 BaseMapChain (ref map) => map.contains_key(key),
448 ConsMapChain (ref map,ref rest) =>
449 (map.contains_key(key)
450 || rest.contains_key(key))
453 // should each_key and each_value operate on shadowed
454 // names? I think not.
455 // delaying implementing this....
456 fn each_key (&self, _f: &fn (&K)->bool) {
457 fail!("unimplemented 2013-02-15T10:01");
460 fn each_value (&self, _f: &fn (&V) -> bool) {
461 fail!("unimplemented 2013-02-15T10:02");
464 // Returns a copy of the value that the name maps to.
465 // Goes down the chain 'til it finds one (or bottom out).
466 fn find (&self, key: &K) -> Option<@V> {
467 match self.get_map().find (key) {
468 Some(ref v) => Some(**v),
469 None => match *self {
470 BaseMapChain (_) => None,
471 ConsMapChain (_,ref rest) => rest.find(key)
476 fn find_in_topmost_frame(&self, key: &K) -> Option<@V> {
477 let map = match *self {
478 BaseMapChain(ref map) => map,
479 ConsMapChain(ref map,_) => map
481 // strip one layer of indirection off the pointer.
482 map.find(key).map(|r| {**r})
485 // insert the binding into the top-level map
486 fn insert (&mut self, key: K, ext: @V) -> bool {
487 // can't abstract over get_map because of flow sensitivity...
489 BaseMapChain (~ref mut map) => map.insert(key, ext),
490 ConsMapChain (~ref mut map,_) => map.insert(key,ext)
493 // insert the binding into the topmost frame for which the binding
494 // associated with 'n' exists and satisfies pred
495 // ... there are definitely some opportunities for abstraction
496 // here that I'm ignoring. (e.g., manufacturing a predicate on
497 // the maps in the chain, and using an abstract "find".
498 fn insert_into_frame(&mut self, key: K, ext: @V, n: K, pred: &fn(&@V)->bool) {
500 BaseMapChain (~ref mut map) => {
501 if satisfies_pred(map,&n,pred) {
504 fail!(~"expected map chain containing satisfying frame")
507 ConsMapChain (~ref mut map, rest) => {
508 if satisfies_pred(map,&n,|v|pred(v)) {
511 rest.insert_into_frame(key,ext,n,pred)
518 // returns true if the binding for 'n' satisfies 'pred' in 'map'
519 fn satisfies_pred<K : Eq + Hash + IterBytes,V>(map : &mut HashMap<K,V>,
524 Some(ref v) => (pred(*v)),
532 use std::hashmap::HashMap;
534 #[test] fn testenv () {
535 let mut a = HashMap::new();
536 a.insert (@"abc",@15);
537 let m = MapChain::new(~a);
538 m.insert (@"def",@16);
539 // FIXME: #4492 (ICE) assert_eq!(m.find(&@"abc"),Some(@15));
540 // .... assert_eq!(m.find(&@"def"),Some(@16));
541 assert_eq!(*(m.find(&@"abc").unwrap()),15);
542 assert_eq!(*(m.find(&@"def").unwrap()),16);
543 let n = m.push_frame();
544 // old bindings are still present:
545 assert_eq!(*(n.find(&@"abc").unwrap()),15);
546 assert_eq!(*(n.find(&@"def").unwrap()),16);
547 n.insert (@"def",@17);
548 // n shows the new binding
549 assert_eq!(*(n.find(&@"abc").unwrap()),15);
550 assert_eq!(*(n.find(&@"def").unwrap()),17);
551 // ... but m still has the old ones
552 // FIXME: #4492: assert_eq!(m.find(&@"abc"),Some(@15));
553 // FIXME: #4492: assert_eq!(m.find(&@"def"),Some(@16));
554 assert_eq!(*(m.find(&@"abc").unwrap()),15);
555 assert_eq!(*(m.find(&@"def").unwrap()),16);