1 // Copyright 2012 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.
15 use codemap::{CodeMap, span, ExpnInfo, ExpandedFrom, dummy_sp};
16 use codemap::{CallInfo, NameAndSpan};
17 use diagnostic::span_handler;
20 use parse::{parser, token};
23 use core::hashmap::linear::LinearMap;
25 // new-style macro! tt code:
27 // SyntaxExpanderTT, SyntaxExpanderTTItem, MacResult,
30 // also note that ast::mac used to have a bunch of extraneous cases and
31 // is now probably a redundant AST node, can be merged with
39 pub type ItemDecorator = @fn(ext_ctxt,
45 pub struct SyntaxExpanderTT {
46 expander: SyntaxExpanderTTFun,
50 pub type SyntaxExpanderTTFun = @fn(ext_ctxt,
55 pub struct SyntaxExpanderTTItem {
56 expander: SyntaxExpanderTTItemFun,
60 pub type SyntaxExpanderTTItemFun = @fn(ext_ctxt,
69 MRAny(@fn() -> @ast::expr,
70 @fn() -> Option<@ast::item>,
75 pub enum SyntaxExtension {
77 // #[auto_encode] and such
78 ItemDecorator(ItemDecorator),
80 // Token-tree expanders
81 NormalTT(SyntaxExpanderTT),
83 // An IdentTT is a macro that has an
84 // identifier in between the name of the
85 // macro and the argument. Currently,
86 // the only examples of this are
87 // macro_rules! and proto!
89 // perhaps macro_rules! will lose its odd special identifier argument,
90 // and this can go away also
91 IdentTT(SyntaxExpanderTTItem),
94 pub type SyntaxEnv = @mut MapChain<Name, Transformer>;
96 // Name : the domain of SyntaxEnvs
97 // want to change these to uints....
98 // note that we use certain strings that are not legal as identifiers
99 // to indicate, for instance, how blocks are supposed to behave.
102 // Transformer : the codomain of SyntaxEnvs
104 // NB: it may seem crazy to lump both of these into one environment;
105 // what would it mean to bind "foo" to BlockLimit(true)? The idea
106 // is that this follows the lead of MTWT, and accommodates growth
107 // toward a more uniform syntax syntax (sorry) where blocks are just
108 // another kind of transformer.
110 pub enum Transformer {
111 // this identifier maps to a syntax extension or macro
113 // should blocks occurring here limit macro scopes?
117 // The base map of methods for expanding syntax extension
118 // AST nodes into full ASTs
119 pub fn syntax_expander_table() -> SyntaxEnv {
120 // utility function to simplify creating NormalTT syntax extensions
121 fn builtin_normal_tt(f: SyntaxExpanderTTFun) -> @Transformer {
122 @SE(NormalTT(SyntaxExpanderTT{expander: f, span: None}))
124 // utility function to simplify creating IdentTT syntax extensions
125 fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer {
126 @SE(IdentTT(SyntaxExpanderTTItem{expander: f, span: None}))
128 let mut syntax_expanders = LinearMap::new();
129 // NB identifier starts with space, and can't conflict with legal idents
130 syntax_expanders.insert(@~" block",
132 syntax_expanders.insert(@~"macro_rules",
134 ext::tt::macro_rules::add_new_extension));
135 syntax_expanders.insert(@~"fmt",
136 builtin_normal_tt(ext::fmt::expand_syntax_ext));
137 syntax_expanders.insert(
139 @SE(ItemDecorator(ext::auto_encode::expand_auto_encode)));
140 syntax_expanders.insert(
142 @SE(ItemDecorator(ext::auto_encode::expand_auto_decode)));
143 syntax_expanders.insert(@~"env",
144 builtin_normal_tt(ext::env::expand_syntax_ext));
145 syntax_expanders.insert(@~"concat_idents",
147 ext::concat_idents::expand_syntax_ext));
148 syntax_expanders.insert(@~"log_syntax",
150 ext::log_syntax::expand_syntax_ext));
151 syntax_expanders.insert(@~"deriving_eq",
153 ext::deriving::expand_deriving_eq)));
154 syntax_expanders.insert(@~"deriving_iter_bytes",
156 ext::deriving::expand_deriving_iter_bytes)));
157 syntax_expanders.insert(@~"deriving_clone",
159 ext::deriving::expand_deriving_clone)));
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(
203 builtin_normal_tt(ext::trace_macros::expand_trace_macros));
204 MapChain::new(~syntax_expanders)
207 // One of these is made during expansion and incrementally updated as we go;
208 // when a macro expansion occurs, the resulting nodes have the backtrace()
209 // -> expn_info of their expansion context stored into their span.
211 fn codemap(@mut self) -> @CodeMap;
212 fn parse_sess(@mut self) -> @mut parse::ParseSess;
213 fn cfg(@mut self) -> ast::crate_cfg;
214 fn call_site(@mut self) -> span;
215 fn print_backtrace(@mut self);
216 fn backtrace(@mut self) -> Option<@ExpnInfo>;
217 fn mod_push(@mut self, mod_name: ast::ident);
218 fn mod_pop(@mut self);
219 fn mod_path(@mut self) -> ~[ast::ident];
220 fn bt_push(@mut self, ei: codemap::ExpnInfo);
221 fn bt_pop(@mut self);
222 fn span_fatal(@mut self, sp: span, msg: &str) -> !;
223 fn span_err(@mut self, sp: span, msg: &str);
224 fn span_warn(@mut self, sp: span, msg: &str);
225 fn span_unimpl(@mut self, sp: span, msg: &str) -> !;
226 fn span_bug(@mut self, sp: span, msg: &str) -> !;
227 fn bug(@mut self, msg: &str) -> !;
228 fn next_id(@mut self) -> ast::node_id;
229 pure fn trace_macros(@mut self) -> bool;
230 fn set_trace_macros(@mut self, x: bool);
231 /* for unhygienic identifier transformation */
232 fn str_of(@mut self, id: ast::ident) -> ~str;
233 fn ident_of(@mut self, st: ~str) -> ast::ident;
236 pub fn mk_ctxt(parse_sess: @mut parse::ParseSess,
237 +cfg: ast::crate_cfg) -> ext_ctxt {
239 parse_sess: @mut parse::ParseSess,
241 backtrace: @mut Option<@ExpnInfo>,
242 mod_path: ~[ast::ident],
245 impl ext_ctxt for CtxtRepr {
246 fn codemap(@mut self) -> @CodeMap { self.parse_sess.cm }
247 fn parse_sess(@mut self) -> @mut parse::ParseSess { self.parse_sess }
248 fn cfg(@mut self) -> ast::crate_cfg { copy self.cfg }
249 fn call_site(@mut self) -> span {
250 match *self.backtrace {
251 Some(@ExpandedFrom(CallInfo {call_site: cs, _})) => cs,
252 None => self.bug(~"missing top span")
255 fn print_backtrace(@mut self) { }
256 fn backtrace(@mut self) -> Option<@ExpnInfo> { *self.backtrace }
257 fn mod_push(@mut self, i: ast::ident) { self.mod_path.push(i); }
258 fn mod_pop(@mut self) { self.mod_path.pop(); }
259 fn mod_path(@mut self) -> ~[ast::ident] { copy self.mod_path }
260 fn bt_push(@mut self, ei: codemap::ExpnInfo) {
262 ExpandedFrom(CallInfo {call_site: cs, callee: ref callee}) => {
264 Some(@ExpandedFrom(CallInfo {
265 call_site: span {lo: cs.lo, hi: cs.hi,
266 expn_info: *self.backtrace},
267 callee: copy *callee}));
271 fn bt_pop(@mut self) {
272 match *self.backtrace {
273 Some(@ExpandedFrom(CallInfo {
274 call_site: span {expn_info: prev, _}, _
276 *self.backtrace = prev
278 _ => self.bug(~"tried to pop without a push")
281 fn span_fatal(@mut self, sp: span, msg: &str) -> ! {
282 self.print_backtrace();
283 self.parse_sess.span_diagnostic.span_fatal(sp, msg);
285 fn span_err(@mut self, sp: span, msg: &str) {
286 self.print_backtrace();
287 self.parse_sess.span_diagnostic.span_err(sp, msg);
289 fn span_warn(@mut self, sp: span, msg: &str) {
290 self.print_backtrace();
291 self.parse_sess.span_diagnostic.span_warn(sp, msg);
293 fn span_unimpl(@mut self, sp: span, msg: &str) -> ! {
294 self.print_backtrace();
295 self.parse_sess.span_diagnostic.span_unimpl(sp, msg);
297 fn span_bug(@mut self, sp: span, msg: &str) -> ! {
298 self.print_backtrace();
299 self.parse_sess.span_diagnostic.span_bug(sp, msg);
301 fn bug(@mut self, msg: &str) -> ! {
302 self.print_backtrace();
303 self.parse_sess.span_diagnostic.handler().bug(msg);
305 fn next_id(@mut self) -> ast::node_id {
306 return parse::next_node_id(self.parse_sess);
308 pure fn trace_macros(@mut self) -> bool {
311 fn set_trace_macros(@mut self, x: bool) {
314 fn str_of(@mut self, id: ast::ident) -> ~str {
315 copy *self.parse_sess.interner.get(id)
317 fn ident_of(@mut self, st: ~str) -> ast::ident {
318 self.parse_sess.interner.intern(@/*bad*/ copy st)
321 let imp: @mut CtxtRepr = @mut CtxtRepr {
322 parse_sess: parse_sess,
324 backtrace: @mut None,
331 pub fn expr_to_str(cx: ext_ctxt, expr: @ast::expr, err_msg: ~str) -> ~str {
333 ast::expr_lit(l) => match l.node {
334 ast::lit_str(s) => copy *s,
335 _ => cx.span_fatal(l.span, err_msg)
337 _ => cx.span_fatal(expr.span, err_msg)
341 pub fn expr_to_ident(cx: ext_ctxt,
343 err_msg: ~str) -> ast::ident {
345 ast::expr_path(p) => {
346 if vec::len(p.types) > 0u || vec::len(p.idents) != 1u {
347 cx.span_fatal(expr.span, err_msg);
351 _ => cx.span_fatal(expr.span, err_msg)
355 pub fn check_zero_tts(cx: ext_ctxt, sp: span, tts: &[ast::token_tree],
358 cx.span_fatal(sp, fmt!("%s takes no arguments", name));
362 pub fn get_single_str_from_tts(cx: ext_ctxt,
364 tts: &[ast::token_tree],
365 name: &str) -> ~str {
367 cx.span_fatal(sp, fmt!("%s takes 1 argument.", name));
371 ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident),
373 cx.span_fatal(sp, fmt!("%s requires a string.", name))
377 pub fn get_exprs_from_tts(cx: ext_ctxt, tts: &[ast::token_tree])
379 let p = parse::new_parser_from_tts(cx.parse_sess(),
381 vec::from_slice(tts));
383 while *p.token != token::EOF {
385 p.eat(&token::COMMA);
387 es.push(p.parse_expr());
392 // in order to have some notion of scoping for macros,
393 // we want to implement the notion of a transformation
396 // This environment maps Names to Transformers.
397 // Initially, this includes macro definitions and
402 // Actually, the following implementation is parameterized
403 // by both key and value types.
405 //impl question: how to implement it? Initially, the
406 // env will contain only macros, so it might be painful
407 // to add an empty frame for every context. Let's just
408 // get it working, first....
410 // NB! the mutability of the underlying maps means that
411 // if expansion is out-of-order, a deeper scope may be
412 // able to refer to a macro that was added to an enclosing
413 // scope lexically later than the deeper scope.
415 // Note on choice of representation: I've been pushed to
416 // use a top-level managed pointer by some difficulties
417 // with pushing and popping functionally, and the ownership
418 // issues. As a result, the values returned by the table
419 // also need to be managed; the &self/... type that Maps
420 // return won't work for things that need to get outside
421 // of that managed pointer. The easiest way to do this
422 // is just to insist that the values in the tables are
423 // managed to begin with.
425 // a transformer env is either a base map or a map on top
427 pub enum MapChain<K,V> {
428 BaseMapChain(~LinearMap<K,@V>),
429 ConsMapChain(~LinearMap<K,@V>,@mut MapChain<K,V>)
433 // get the map from an env frame
434 impl <K: Eq + Hash + IterBytes ,V: Copy> MapChain<K,V>{
436 // Constructor. I don't think we need a zero-arg one.
437 static fn new(+init: ~LinearMap<K,@V>) -> @mut MapChain<K,V> {
438 @mut BaseMapChain(init)
441 // add a new frame to the environment (functionally)
442 fn push_frame (@mut self) -> @mut MapChain<K,V> {
443 @mut ConsMapChain(~LinearMap::new() ,self)
446 // no need for pop, it'll just be functional.
450 // ugh: can't get this to compile with mut because of the
451 // lack of flow sensitivity.
452 fn get_map(&self) -> &self/LinearMap<K,@V> {
454 BaseMapChain (~ref map) => map,
455 ConsMapChain (~ref map,_) => map
459 // traits just don't work anywhere...?
460 //pub impl Map<Name,SyntaxExtension> for MapChain {
462 pure fn contains_key (&self, key: &K) -> bool {
464 BaseMapChain (ref map) => map.contains_key(key),
465 ConsMapChain (ref map,ref rest) =>
466 (map.contains_key(key)
467 || rest.contains_key(key))
470 // should each_key and each_value operate on shadowed
471 // names? I think not.
472 // delaying implementing this....
473 pure fn each_key (&self, _f: &fn (&K)->bool) {
474 fail!(~"unimplemented 2013-02-15T10:01");
477 pure fn each_value (&self, _f: &fn (&V) -> bool) {
478 fail!(~"unimplemented 2013-02-15T10:02");
481 // Returns a copy of the value that the name maps to.
482 // Goes down the chain 'til it finds one (or bottom out).
483 fn find (&self, key: &K) -> Option<@V> {
484 match self.get_map().find (key) {
485 Some(ref v) => Some(**v),
486 None => match *self {
487 BaseMapChain (_) => None,
488 ConsMapChain (_,ref rest) => rest.find(key)
493 // insert the binding into the top-level map
494 fn insert (&mut self, +key: K, +ext: @V) -> bool {
495 // can't abstract over get_map because of flow sensitivity...
497 BaseMapChain (~ref mut map) => map.insert(key, ext),
498 ConsMapChain (~ref mut map,_) => map.insert(key,ext)
507 use util::testing::check_equal;
508 use core::hashmap::linear::LinearMap;
510 #[test] fn testenv () {
511 let mut a = LinearMap::new();
512 a.insert (@~"abc",@15);
513 let m = MapChain::new(~a);
514 m.insert (@~"def",@16);
515 // FIXME: #4492 (ICE) check_equal(m.find(&@~"abc"),Some(@15));
516 // .... check_equal(m.find(&@~"def"),Some(@16));
517 check_equal(*(m.find(&@~"abc").get()),15);
518 check_equal(*(m.find(&@~"def").get()),16);
519 let n = m.push_frame();
520 // old bindings are still present:
521 check_equal(*(n.find(&@~"abc").get()),15);
522 check_equal(*(n.find(&@~"def").get()),16);
523 n.insert (@~"def",@17);
524 // n shows the new binding
525 check_equal(*(n.find(&@~"abc").get()),15);
526 check_equal(*(n.find(&@~"def").get()),17);
527 // ... but m still has the old ones
528 // FIXME: #4492: check_equal(m.find(&@~"abc"),Some(@15));
529 // FIXME: #4492: check_equal(m.find(&@~"def"),Some(@16));
530 check_equal(*(m.find(&@~"abc").get()),15);
531 check_equal(*(m.find(&@~"def").get()),16);
539 // indent-tabs-mode: nil
541 // buffer-file-coding-system: utf-8-unix