about summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorPaul Stansifer <paul.stansifer@gmail.com>2012-11-19 20:31:22 -0500
committerGraydon Hoare <graydon@mozilla.com>2012-11-29 12:09:10 -0800
commitcf26a7d7b952cf94fb4bb185c2eb0cb47e4551ce (patch)
treef1c174a7da697aed0292684e2dbe83d296c4b4cd /src/libsyntax/ext
parentee076f63f910fe2b132904ad05d0cda178ff1ec6 (diff)
downloadrust-cf26a7d7b952cf94fb4bb185c2eb0cb47e4551ce.tar.gz
rust-cf26a7d7b952cf94fb4bb185c2eb0cb47e4551ce.zip
Make it possible to expand stmt macros.
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/base.rs16
-rw-r--r--src/libsyntax/ext/expand.rs66
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs7
3 files changed, 72 insertions, 17 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 3701614f137..01193a0b483 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -44,7 +44,7 @@ type syntax_expander_tt_item_
 enum mac_result {
     mr_expr(@ast::expr),
     mr_item(@ast::item),
-    mr_expr_or_item(fn@()-> @ast::expr, fn@()-> Option<@ast::item>),
+    mr_any(fn@()-> @ast::expr, fn@()-> Option<@ast::item>, fn@()->@ast::stmt),
     mr_def(macro_def)
 }
 
@@ -109,18 +109,18 @@ fn syntax_expander_table() -> HashMap<~str, syntax_extension> {
                                 ext::deriving::expand_deriving_iter_bytes));
 
     // Quasi-quoting expanders
-    syntax_expanders.insert(~"quote_tokens",
-                            builtin_expr_tt(ext::quote::expand_quote_tokens));
+    syntax_expanders.insert(
+        ~"quote_tokens", builtin_normal_tt(ext::quote::expand_quote_tokens));
     syntax_expanders.insert(~"quote_expr",
-                            builtin_expr_tt(ext::quote::expand_quote_expr));
+                            builtin_normal_tt(ext::quote::expand_quote_expr));
     syntax_expanders.insert(~"quote_type",
-                            builtin_expr_tt(ext::quote::expand_quote_type));
+                            builtin_normal_tt(ext::quote::expand_quote_type));
     syntax_expanders.insert(~"quote_item",
-                            builtin_expr_tt(ext::quote::expand_quote_item));
+                            builtin_normal_tt(ext::quote::expand_quote_item));
     syntax_expanders.insert(~"quote_pat",
-                            builtin_expr_tt(ext::quote::expand_quote_pat));
+                            builtin_normal_tt(ext::quote::expand_quote_pat));
     syntax_expanders.insert(~"quote_stmt",
-                            builtin_expr_tt(ext::quote::expand_quote_stmt));
+                            builtin_normal_tt(ext::quote::expand_quote_stmt));
 
     syntax_expanders.insert(~"line",
                             builtin(ext::source_util::expand_line));
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index c296938d5d2..b997106b4ed 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1,7 +1,7 @@
 use std::map::HashMap;
 
 use ast::{crate, expr_, expr_mac, mac_invoc, mac_invoc_tt,
-             tt_delim, tt_tok, item_mac};
+          tt_delim, tt_tok, item_mac, stmt_, stmt_mac};
 use fold::*;
 use ext::base::*;
 use ext::qquote::{qq_helper};
@@ -20,9 +20,9 @@ fn expand_expr(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt,
       // entry-point for all syntax extensions.
           expr_mac(mac) => {
 
-            // Old-style macros, for compatibility, will erase this whole
-            // block once we've transitioned.
             match mac.node {
+              // Old-style macros. For compatibility, will erase this whole
+              // block once we've transitioned.
               mac_invoc(pth, args, body) => {
                 assert (vec::len(pth.idents) > 0u);
                 /* using idents and token::special_idents would make the
@@ -81,7 +81,7 @@ fn expand_expr(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt,
                   Some(normal_tt({expander: exp, span: exp_sp})) => {
                     let expanded = match exp(cx, mac.span, tts) {
                       mr_expr(e) => e,
-                      mr_expr_or_item(expr_maker,_) => expr_maker(),
+                      mr_any(expr_maker,_,_) => expr_maker(),
                       _ => cx.span_fatal(
                           pth.span, fmt!("non-expr macro in expr pos: %s",
                                          *extname))
@@ -234,7 +234,7 @@ fn expand_item_mac(exts: HashMap<~str, syntax_extension>,
             mr_expr(_) => cx.span_fatal(pth.span,
                                         ~"expr macro in item position: " +
                                         *extname),
-            mr_expr_or_item(_, item_maker) =>
+            mr_any(_, item_maker, _) =>
                 option::chain(item_maker(), |i| {fld.fold_item(i)}),
             mr_def(mdef) => {
                 exts.insert(mdef.name, mdef.ext);
@@ -248,6 +248,59 @@ fn expand_item_mac(exts: HashMap<~str, syntax_extension>,
     }
 }
 
+fn expand_stmt(exts: HashMap<~str, syntax_extension>, cx: ext_ctxt,
+               && s: stmt_, sp: span, fld: ast_fold,
+               orig: fn@(&&s: stmt_, span, ast_fold) -> (stmt_, span))
+    -> (stmt_, span)
+{
+    return match s {
+        stmt_mac(mac) => {
+            match mac.node {
+                mac_invoc_tt(pth, tts) => {
+                    assert(vec::len(pth.idents) == 1u);
+                    let extname = cx.parse_sess().interner.get(pth.idents[0]);
+                    match exts.find(*extname) {
+                        None => {
+                            cx.span_fatal(
+                                pth.span,
+                                fmt!("macro undefined: '%s'", *extname))
+                        }
+                        Some(normal_tt({expander: exp, span: exp_sp})) => {
+                            let expanded = match exp(cx, mac.span, tts) {
+                                mr_expr(e) =>
+                                @{node: ast::stmt_expr(e, cx.next_id()),
+                                  span: e.span},
+                                mr_any(_,_,stmt_mkr) => stmt_mkr(),
+                                _ => cx.span_fatal(
+                                    pth.span,
+                                    fmt!("non-stmt macro in stmt pos: %s",
+                                         *extname))
+                            };
+
+                            cx.bt_push(ExpandedFrom(
+                                {call_site: sp,
+                                 callie: {name: *extname, span: exp_sp}}));
+                            //keep going, outside-in
+                            let fully_expanded = fld.fold_stmt(expanded).node;
+                            cx.bt_pop();
+
+                            (fully_expanded, sp)
+                        }
+                        _ => {
+                            cx.span_fatal(pth.span,
+                                          fmt!("'%s' is not a tt-style macro",
+                                               *extname))
+                        }
+                    }
+                }
+                _ => cx.span_bug(mac.span, ~"naked syntactic bit")
+            }
+        }
+        _ => orig(s, sp, fld)
+    };
+}
+
+
 fn new_span(cx: ext_ctxt, sp: span) -> span {
     /* this discards information in the case of macro-defining macros */
     return span {lo: sp.lo, hi: sp.hi, expn_info: cx.backtrace()};
@@ -298,7 +351,8 @@ fn expand_crate(parse_sess: parse::parse_sess,
         @{fold_expr: |a,b,c| expand_expr(exts, cx, a, b, c, afp.fold_expr),
           fold_mod: |a,b| expand_mod_items(exts, cx, a, b, afp.fold_mod),
           fold_item: |a,b| expand_item(exts, cx, a, b, afp.fold_item),
-          new_span: |a|new_span(cx, a),
+          fold_stmt: |a,b,c| expand_stmt(exts, cx, a, b, c, afp.fold_stmt),
+          new_span: |a| new_span(cx, a),
           .. *afp};
     let f = make_fold(f_pre);
     let cm = parse_expr_from_source_str(~"<core-macros>",
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 012e421718a..1c62c9b2a6d 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -1,4 +1,4 @@
-use base::{ext_ctxt, mac_result, mr_expr_or_item, mr_def, normal_tt};
+use base::{ext_ctxt, mac_result, mr_any, mr_def, normal_tt};
 use codemap::span;
 use ast::{ident, matcher_, matcher, match_tok,
              match_nonterminal, match_seq, tt_delim};
@@ -92,8 +92,9 @@ fn add_new_extension(cx: ext_ctxt, sp: span, name: ident,
 
                     // Let the context choose how to interpret the result.
                     // Weird, but useful for X-macros.
-                    return mr_expr_or_item(|| p.parse_expr(),
-                                           || p.parse_item(~[/* no attrs*/]));
+                    return mr_any(|| p.parse_expr(),
+                                  || p.parse_item(~[/* no attrs*/]),
+                                  || p.parse_stmt(~[/* no attrs*/]));
                   }
                   failure(sp, msg) => if sp.lo >= best_fail_spot.lo {
                     best_fail_spot = sp;