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.
13 use codemap::{CodeMap, span, ExpnInfo, ExpandedFrom};
14 use codemap::CallInfo;
15 use diagnostic::span_handler;
20 use core::hashmap::HashMap;
22 // new-style macro! tt code:
24 // SyntaxExpanderTT, SyntaxExpanderTTItem, MacResult,
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
36 pub type ItemDecorator = @fn(@ext_ctxt,
42 pub struct SyntaxExpanderTT {
43 expander: SyntaxExpanderTTFun,
47 pub type SyntaxExpanderTTFun = @fn(@ext_ctxt,
52 pub struct SyntaxExpanderTTItem {
53 expander: SyntaxExpanderTTItemFun,
57 pub type SyntaxExpanderTTItemFun = @fn(@ext_ctxt,
66 MRAny(@fn() -> @ast::expr,
67 @fn() -> Option<@ast::item>,
72 pub enum SyntaxExtension {
74 // #[auto_encode] and such
75 ItemDecorator(ItemDecorator),
77 // Token-tree expanders
78 NormalTT(SyntaxExpanderTT),
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!
86 // perhaps macro_rules! will lose its odd special identifier argument,
87 // and this can go away also
88 IdentTT(SyntaxExpanderTTItem),
91 pub type SyntaxEnv = @mut MapChain<Name, Transformer>;
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.
99 // Transformer : the codomain of SyntaxEnvs
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.
107 pub enum Transformer {
108 // this identifier maps to a syntax extension or macro
110 // should blocks occurring here limit macro scopes?
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}))
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}))
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",
129 syntax_expanders.insert(@~"macro_rules",
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(
136 @SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
137 syntax_expanders.insert(
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",
144 ext::concat_idents::expand_syntax_ext));
145 syntax_expanders.insert(@~"log_syntax",
147 ext::log_syntax::expand_syntax_ext));
148 syntax_expanders.insert(@~"deriving",
150 ext::deriving::expand_meta_deriving)));
151 syntax_expanders.insert(@~"deriving_eq",
153 ext::deriving::eq::expand_deriving_obsolete)));
154 syntax_expanders.insert(@~"deriving_iter_bytes",
156 ext::deriving::iter_bytes::expand_deriving_obsolete)));
157 syntax_expanders.insert(@~"deriving_clone",
159 ext::deriving::clone::expand_deriving_obsolete)));
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));
175 syntax_expanders.insert(@~"line",
177 ext::source_util::expand_line));
178 syntax_expanders.insert(@~"col",
180 ext::source_util::expand_col));
181 syntax_expanders.insert(@~"file",
183 ext::source_util::expand_file));
184 syntax_expanders.insert(@~"stringify",
186 ext::source_util::expand_stringify));
187 syntax_expanders.insert(@~"include",
189 ext::source_util::expand_include));
190 syntax_expanders.insert(@~"include_str",
192 ext::source_util::expand_include_str));
193 syntax_expanders.insert(@~"include_bin",
195 ext::source_util::expand_include_bin));
196 syntax_expanders.insert(@~"module_path",
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(
205 builtin_normal_tt(ext::trace_macros::expand_trace_macros));
206 MapChain::new(~syntax_expanders)
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.
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;
238 pub fn mk_ctxt(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg)
241 parse_sess: @mut parse::ParseSess,
243 backtrace: @mut Option<@ExpnInfo>,
244 mod_path: ~[ast::ident],
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")
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) {
264 ExpandedFrom(CallInfo {call_site: cs, callee: ref callee}) => {
266 Some(@ExpandedFrom(CallInfo {
267 call_site: span {lo: cs.lo, hi: cs.hi,
268 expn_info: *self.backtrace},
269 callee: copy *callee}));
273 fn bt_pop(@mut self) {
274 match *self.backtrace {
275 Some(@ExpandedFrom(CallInfo {
276 call_site: span {expn_info: prev, _}, _
278 *self.backtrace = prev
280 _ => self.bug(~"tried to pop without a push")
283 fn span_fatal(@mut self, sp: span, msg: &str) -> ! {
284 self.print_backtrace();
285 self.parse_sess.span_diagnostic.span_fatal(sp, msg);
287 fn span_err(@mut self, sp: span, msg: &str) {
288 self.print_backtrace();
289 self.parse_sess.span_diagnostic.span_err(sp, msg);
291 fn span_warn(@mut self, sp: span, msg: &str) {
292 self.print_backtrace();
293 self.parse_sess.span_diagnostic.span_warn(sp, msg);
295 fn span_unimpl(@mut self, sp: span, msg: &str) -> ! {
296 self.print_backtrace();
297 self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
299 fn span_bug(@mut self, sp: span, msg: &str) -> ! {
300 self.print_backtrace();
301 self.parse_sess.span_diagnostic.span_bug(sp, msg);
303 fn bug(@mut self, msg: &str) -> ! {
304 self.print_backtrace();
305 self.parse_sess.span_diagnostic.handler().bug(msg);
307 fn next_id(@mut self) -> ast::node_id {
308 return parse::next_node_id(self.parse_sess);
310 fn trace_macros(@mut self) -> bool {
313 fn set_trace_macros(@mut self, x: bool) {
316 fn str_of(@mut self, id: ast::ident) -> ~str {
317 copy *self.parse_sess.interner.get(id)
319 fn ident_of(@mut self, st: ~str) -> ast::ident {
320 self.parse_sess.interner.intern(@/*bad*/ copy st)
323 let imp: @mut CtxtRepr = @mut CtxtRepr {
324 parse_sess: parse_sess,
326 backtrace: @mut None,
333 pub fn expr_to_str(cx: @ext_ctxt, expr: @ast::expr, err_msg: ~str) -> ~str {
335 ast::expr_lit(l) => match l.node {
336 ast::lit_str(s) => copy *s,
337 _ => cx.span_fatal(l.span, err_msg)
339 _ => cx.span_fatal(expr.span, err_msg)
343 pub fn expr_to_ident(cx: @ext_ctxt,
345 err_msg: ~str) -> ast::ident {
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);
353 _ => cx.span_fatal(expr.span, err_msg)
357 pub fn check_zero_tts(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree],
360 cx.span_fatal(sp, fmt!("%s takes no arguments", name));
364 pub fn get_single_str_from_tts(cx: @ext_ctxt,
366 tts: &[ast::token_tree],
367 name: &str) -> ~str {
369 cx.span_fatal(sp, fmt!("%s takes 1 argument.", name));
373 ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident),
375 cx.span_fatal(sp, fmt!("%s requires a string.", name))
379 pub fn get_exprs_from_tts(cx: @ext_ctxt, tts: &[ast::token_tree])
381 let p = parse::new_parser_from_tts(cx.parse_sess(),
383 vec::from_slice(tts));
385 while *p.token != token::EOF {
387 p.eat(&token::COMMA);
389 es.push(p.parse_expr());
394 // in order to have some notion of scoping for macros,
395 // we want to implement the notion of a transformation
398 // This environment maps Names to Transformers.
399 // Initially, this includes macro definitions and
404 // Actually, the following implementation is parameterized
405 // by both key and value types.
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....
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.
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.
427 // a transformer env is either a base map or a map on top
429 pub enum MapChain<K,V> {
430 BaseMapChain(~HashMap<K,@V>),
431 ConsMapChain(~HashMap<K,@V>,@mut MapChain<K,V>)
435 // get the map from an env frame
436 impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{
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)
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)
448 // no need for pop, it'll just be functional.
452 // ugh: can't get this to compile with mut because of the
453 // lack of flow sensitivity.
455 fn get_map(&self) -> &'self HashMap<K,@V> {
457 BaseMapChain (~ref map) => map,
458 ConsMapChain (~ref map,_) => map
462 // ugh: can't get this to compile with mut because of the
463 // lack of flow sensitivity.
465 fn get_map<'a>(&'a self) -> &'a HashMap<K,@V> {
467 BaseMapChain (~ref map) => map,
468 ConsMapChain (~ref map,_) => map
472 // traits just don't work anywhere...?
473 //pub impl Map<Name,SyntaxExtension> for MapChain {
475 fn contains_key (&self, key: &K) -> bool {
477 BaseMapChain (ref map) => map.contains_key(key),
478 ConsMapChain (ref map,ref rest) =>
479 (map.contains_key(key)
480 || rest.contains_key(key))
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");
490 fn each_value (&self, _f: &fn (&V) -> bool) {
491 fail!(~"unimplemented 2013-02-15T10:02");
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)
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...
510 BaseMapChain (~ref mut map) => map.insert(key, ext),
511 ConsMapChain (~ref mut map,_) => map.insert(key,ext)
520 use core::hashmap::HashMap;
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);