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(intern(&"ifmt"),
143 builtin_normal_tt(ext::ifmt::expand_syntax_ext));
144 syntax_expanders.insert(
145 intern(&"auto_encode"),
146 @SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
147 syntax_expanders.insert(
148 intern(&"auto_decode"),
149 @SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
150 syntax_expanders.insert(intern(&"env"),
151 builtin_normal_tt(ext::env::expand_syntax_ext));
152 syntax_expanders.insert(intern("bytes"),
153 builtin_normal_tt(ext::bytes::expand_syntax_ext));
154 syntax_expanders.insert(intern("concat_idents"),
156 ext::concat_idents::expand_syntax_ext));
157 syntax_expanders.insert(intern(&"log_syntax"),
159 ext::log_syntax::expand_syntax_ext));
160 syntax_expanders.insert(intern(&"deriving"),
162 ext::deriving::expand_meta_deriving)));
164 // Quasi-quoting expanders
165 syntax_expanders.insert(intern(&"quote_tokens"),
166 builtin_normal_tt(ext::quote::expand_quote_tokens));
167 syntax_expanders.insert(intern(&"quote_expr"),
168 builtin_normal_tt(ext::quote::expand_quote_expr));
169 syntax_expanders.insert(intern(&"quote_ty"),
170 builtin_normal_tt(ext::quote::expand_quote_ty));
171 syntax_expanders.insert(intern(&"quote_item"),
172 builtin_normal_tt(ext::quote::expand_quote_item));
173 syntax_expanders.insert(intern(&"quote_pat"),
174 builtin_normal_tt(ext::quote::expand_quote_pat));
175 syntax_expanders.insert(intern(&"quote_stmt"),
176 builtin_normal_tt(ext::quote::expand_quote_stmt));
178 syntax_expanders.insert(intern(&"line"),
180 ext::source_util::expand_line));
181 syntax_expanders.insert(intern(&"col"),
183 ext::source_util::expand_col));
184 syntax_expanders.insert(intern(&"file"),
186 ext::source_util::expand_file));
187 syntax_expanders.insert(intern(&"stringify"),
189 ext::source_util::expand_stringify));
190 syntax_expanders.insert(intern(&"include"),
192 ext::source_util::expand_include));
193 syntax_expanders.insert(intern(&"include_str"),
195 ext::source_util::expand_include_str));
196 syntax_expanders.insert(intern(&"include_bin"),
198 ext::source_util::expand_include_bin));
199 syntax_expanders.insert(intern(&"module_path"),
201 ext::source_util::expand_mod));
202 syntax_expanders.insert(intern(&"asm"),
203 builtin_normal_tt(ext::asm::expand_asm));
204 syntax_expanders.insert(intern(&"cfg"),
205 builtin_normal_tt(ext::cfg::expand_cfg));
206 syntax_expanders.insert(
207 intern(&"trace_macros"),
208 builtin_normal_tt(ext::trace_macros::expand_trace_macros));
209 MapChain::new(~syntax_expanders)
212 // One of these is made during expansion and incrementally updated as we go;
213 // when a macro expansion occurs, the resulting nodes have the backtrace()
214 // -> expn_info of their expansion context stored into their span.
216 parse_sess: @mut parse::ParseSess,
217 cfg: ast::CrateConfig,
218 backtrace: @mut Option<@ExpnInfo>,
220 // These two @mut's should really not be here,
221 // but the self types for CtxtRepr are all wrong
222 // and there are bugs in the code for object
223 // types that make this hard to get right at the
224 // moment. - nmatsakis
225 mod_path: @mut ~[ast::ident],
230 pub fn new(parse_sess: @mut parse::ParseSess, cfg: ast::CrateConfig)
233 parse_sess: parse_sess,
235 backtrace: @mut None,
237 trace_mac: @mut false
241 pub fn codemap(&self) -> @CodeMap { self.parse_sess.cm }
242 pub fn parse_sess(&self) -> @mut parse::ParseSess { self.parse_sess }
243 pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
244 pub fn call_site(&self) -> span {
245 match *self.backtrace {
246 Some(@ExpnInfo {call_site: cs, _}) => cs,
247 None => self.bug("missing top span")
250 pub fn print_backtrace(&self) { }
251 pub fn backtrace(&self) -> Option<@ExpnInfo> { *self.backtrace }
252 pub fn mod_push(&self, i: ast::ident) { self.mod_path.push(i); }
253 pub fn mod_pop(&self) { self.mod_path.pop(); }
254 pub fn mod_path(&self) -> ~[ast::ident] { (*self.mod_path).clone() }
255 pub fn bt_push(&self, ei: codemap::ExpnInfo) {
257 ExpnInfo {call_site: cs, callee: ref callee} => {
260 call_site: span {lo: cs.lo, hi: cs.hi,
261 expn_info: *self.backtrace},
266 pub fn bt_pop(&self) {
267 match *self.backtrace {
269 call_site: span {expn_info: prev, _}, _}) => {
270 *self.backtrace = prev
272 _ => self.bug("tried to pop without a push")
275 pub fn span_fatal(&self, sp: span, msg: &str) -> ! {
276 self.print_backtrace();
277 self.parse_sess.span_diagnostic.span_fatal(sp, msg);
279 pub fn span_err(&self, sp: span, msg: &str) {
280 self.print_backtrace();
281 self.parse_sess.span_diagnostic.span_err(sp, msg);
283 pub fn span_warn(&self, sp: span, msg: &str) {
284 self.print_backtrace();
285 self.parse_sess.span_diagnostic.span_warn(sp, msg);
287 pub fn span_unimpl(&self, sp: span, msg: &str) -> ! {
288 self.print_backtrace();
289 self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
291 pub fn span_bug(&self, sp: span, msg: &str) -> ! {
292 self.print_backtrace();
293 self.parse_sess.span_diagnostic.span_bug(sp, msg);
295 pub fn bug(&self, msg: &str) -> ! {
296 self.print_backtrace();
297 self.parse_sess.span_diagnostic.handler().bug(msg);
299 pub fn next_id(&self) -> ast::NodeId {
300 parse::next_node_id(self.parse_sess)
302 pub fn trace_macros(&self) -> bool {
305 pub fn set_trace_macros(&self, x: bool) {
308 pub fn str_of(&self, id: ast::ident) -> @str {
311 pub fn ident_of(&self, st: &str) -> ast::ident {
316 pub fn expr_to_str(cx: @ExtCtxt, expr: @ast::expr, err_msg: ~str) -> @str {
318 ast::expr_lit(l) => match l.node {
319 ast::lit_str(s) => s,
320 _ => cx.span_fatal(l.span, err_msg)
322 _ => cx.span_fatal(expr.span, err_msg)
326 pub fn expr_to_ident(cx: @ExtCtxt,
328 err_msg: &str) -> ast::ident {
330 ast::expr_path(ref p) => {
331 if p.types.len() > 0u || p.idents.len() != 1u {
332 cx.span_fatal(expr.span, err_msg);
336 _ => cx.span_fatal(expr.span, err_msg)
340 pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
343 cx.span_fatal(sp, fmt!("%s takes no arguments", name));
347 pub fn get_single_str_from_tts(cx: @ExtCtxt,
349 tts: &[ast::token_tree],
350 name: &str) -> @str {
352 cx.span_fatal(sp, fmt!("%s takes 1 argument.", name));
356 ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident),
358 cx.span_fatal(sp, fmt!("%s requires a string.", name))
362 pub fn get_exprs_from_tts(cx: @ExtCtxt,
364 tts: &[ast::token_tree]) -> ~[@ast::expr] {
365 let p = parse::new_parser_from_tts(cx.parse_sess(),
369 while *p.token != token::EOF {
370 if es.len() != 0 && !p.eat(&token::COMMA) {
371 cx.span_fatal(sp, "expected token: `,`");
373 es.push(p.parse_expr());
378 // in order to have some notion of scoping for macros,
379 // we want to implement the notion of a transformation
382 // This environment maps Names to Transformers.
383 // Initially, this includes macro definitions and
388 // Actually, the following implementation is parameterized
389 // by both key and value types.
391 //impl question: how to implement it? Initially, the
392 // env will contain only macros, so it might be painful
393 // to add an empty frame for every context. Let's just
394 // get it working, first....
396 // NB! the mutability of the underlying maps means that
397 // if expansion is out-of-order, a deeper scope may be
398 // able to refer to a macro that was added to an enclosing
399 // scope lexically later than the deeper scope.
401 // Note on choice of representation: I've been pushed to
402 // use a top-level managed pointer by some difficulties
403 // with pushing and popping functionally, and the ownership
404 // issues. As a result, the values returned by the table
405 // also need to be managed; the &'self ... type that Maps
406 // return won't work for things that need to get outside
407 // of that managed pointer. The easiest way to do this
408 // is just to insist that the values in the tables are
409 // managed to begin with.
411 // a transformer env is either a base map or a map on top
413 pub enum MapChain<K,V> {
414 BaseMapChain(~HashMap<K,@V>),
415 ConsMapChain(~HashMap<K,@V>,@mut MapChain<K,V>)
419 // get the map from an env frame
420 impl <K: Eq + Hash + IterBytes + 'static, V: 'static> MapChain<K,V>{
421 // Constructor. I don't think we need a zero-arg one.
422 fn new(init: ~HashMap<K,@V>) -> @mut MapChain<K,V> {
423 @mut BaseMapChain(init)
426 // add a new frame to the environment (functionally)
427 fn push_frame (@mut self) -> @mut MapChain<K,V> {
428 @mut ConsMapChain(~HashMap::new() ,self)
431 // no need for pop, it'll just be functional.
435 // ugh: can't get this to compile with mut because of the
436 // lack of flow sensitivity.
437 fn get_map<'a>(&'a self) -> &'a HashMap<K,@V> {
439 BaseMapChain (~ref map) => map,
440 ConsMapChain (~ref map,_) => map
444 // traits just don't work anywhere...?
445 //impl Map<Name,SyntaxExtension> for MapChain {
447 fn contains_key (&self, key: &K) -> bool {
449 BaseMapChain (ref map) => map.contains_key(key),
450 ConsMapChain (ref map,ref rest) =>
451 (map.contains_key(key)
452 || rest.contains_key(key))
455 // should each_key and each_value operate on shadowed
456 // names? I think not.
457 // delaying implementing this....
458 fn each_key (&self, _f: &fn (&K)->bool) {
459 fail!("unimplemented 2013-02-15T10:01");
462 fn each_value (&self, _f: &fn (&V) -> bool) {
463 fail!("unimplemented 2013-02-15T10:02");
466 // Returns a copy of the value that the name maps to.
467 // Goes down the chain 'til it finds one (or bottom out).
468 fn find (&self, key: &K) -> Option<@V> {
469 match self.get_map().find (key) {
470 Some(ref v) => Some(**v),
471 None => match *self {
472 BaseMapChain (_) => None,
473 ConsMapChain (_,ref rest) => rest.find(key)
478 fn find_in_topmost_frame(&self, key: &K) -> Option<@V> {
479 let map = match *self {
480 BaseMapChain(ref map) => map,
481 ConsMapChain(ref map,_) => map
483 // strip one layer of indirection off the pointer.
484 map.find(key).map_move(|r| {*r})
487 // insert the binding into the top-level map
488 fn insert (&mut self, key: K, ext: @V) -> bool {
489 // can't abstract over get_map because of flow sensitivity...
491 BaseMapChain (~ref mut map) => map.insert(key, ext),
492 ConsMapChain (~ref mut map,_) => map.insert(key,ext)
495 // insert the binding into the topmost frame for which the binding
496 // associated with 'n' exists and satisfies pred
497 // ... there are definitely some opportunities for abstraction
498 // here that I'm ignoring. (e.g., manufacturing a predicate on
499 // the maps in the chain, and using an abstract "find".
500 fn insert_into_frame(&mut self, key: K, ext: @V, n: K, pred: &fn(&@V)->bool) {
502 BaseMapChain (~ref mut map) => {
503 if satisfies_pred(map,&n,pred) {
506 fail!(~"expected map chain containing satisfying frame")
509 ConsMapChain (~ref mut map, rest) => {
510 if satisfies_pred(map,&n,|v|pred(v)) {
513 rest.insert_into_frame(key,ext,n,pred)
520 // returns true if the binding for 'n' satisfies 'pred' in 'map'
521 fn satisfies_pred<K : Eq + Hash + IterBytes,V>(map : &mut HashMap<K,V>,
526 Some(ref v) => (pred(*v)),
534 use std::hashmap::HashMap;
536 #[test] fn testenv () {
537 let mut a = HashMap::new();
538 a.insert (@"abc",@15);
539 let m = MapChain::new(~a);
540 m.insert (@"def",@16);
541 // FIXME: #4492 (ICE) assert_eq!(m.find(&@"abc"),Some(@15));
542 // .... assert_eq!(m.find(&@"def"),Some(@16));
543 assert_eq!(*(m.find(&@"abc").unwrap()),15);
544 assert_eq!(*(m.find(&@"def").unwrap()),16);
545 let n = m.push_frame();
546 // old bindings are still present:
547 assert_eq!(*(n.find(&@"abc").unwrap()),15);
548 assert_eq!(*(n.find(&@"def").unwrap()),16);
549 n.insert (@"def",@17);
550 // n shows the new binding
551 assert_eq!(*(n.find(&@"abc").unwrap()),15);
552 assert_eq!(*(n.find(&@"def").unwrap()),17);
553 // ... but m still has the old ones
554 // FIXME: #4492: assert_eq!(m.find(&@"abc"),Some(@15));
555 // FIXME: #4492: assert_eq!(m.find(&@"def"),Some(@16));
556 assert_eq!(*(m.find(&@"abc").unwrap()),15);
557 assert_eq!(*(m.find(&@"def").unwrap()),16);