about summary refs log tree commit diff
path: root/src/libsyntax/ext
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-05-19 09:45:37 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-05-21 23:00:57 +0000
commit7f30eef2eee5d57bc9759766ec7f62d931f8993b (patch)
treea84b9fc5e429c48a8f63351c027191ed91f85b06 /src/libsyntax/ext
parent179539f6eb61f75244a0dde641b6e4e09c0921ec (diff)
downloadrust-7f30eef2eee5d57bc9759766ec7f62d931f8993b.tar.gz
rust-7f30eef2eee5d57bc9759766ec7f62d931f8993b.zip
Introduce `MacroGenerable` trait
Diffstat (limited to 'src/libsyntax/ext')
-rw-r--r--src/libsyntax/ext/expand.rs99
1 files changed, 46 insertions, 53 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index f243706eecb..b2ebe0e0145 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -35,6 +35,40 @@ use std_inject;
 use std::collections::HashSet;
 use std::env;
 
+trait MacroGenerable: Sized {
+    fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self>;
+    fn fold_with<F: Folder>(self, folder: &mut F) -> Self;
+    fn dummy(span: Span) -> Self;
+    fn kind_name() -> &'static str;
+}
+
+macro_rules! impl_macro_generable {
+    ($($ty:ty: $kind_name:expr, .$make:ident, $(.$fold:ident)* $(lift .$fold_elt:ident)*,
+               |$span:ident| $dummy:expr;)*) => { $(
+        impl MacroGenerable for $ty {
+            fn kind_name() -> &'static str { $kind_name }
+            fn make_with<'a>(result: Box<MacResult + 'a>) -> Option<Self> { result.$make() }
+            fn fold_with<F: Folder>(self, folder: &mut F) -> Self {
+                $( folder.$fold(self) )*
+                $( self.into_iter().flat_map(|item| folder. $fold_elt (item)).collect() )*
+            }
+            fn dummy($span: Span) -> Self { $dummy }
+        }
+    )* }
+}
+
+impl_macro_generable! {
+    P<ast::Expr>: "expression", .make_expr, .fold_expr, |span| DummyResult::raw_expr(span);
+    P<ast::Pat>:  "pattern",    .make_pat,  .fold_pat,  |span| P(DummyResult::raw_pat(span));
+    P<ast::Ty>:   "type",       .make_ty,   .fold_ty,   |span| DummyResult::raw_ty(span);
+    SmallVector<ast::ImplItem>:
+        "impl item", .make_impl_items, lift .fold_impl_item, |_span| SmallVector::zero();
+    SmallVector<P<ast::Item>>:
+        "item",      .make_items,      lift .fold_item,      |_span| SmallVector::zero();
+    SmallVector<ast::Stmt>:
+        "statement", .make_stmts,      lift .fold_stmt,      |_span| SmallVector::zero();
+}
+
 // this function is called to detect use of feature-gated or invalid attributes
 // on macro invoations since they will not be detected after macro expansion
 fn check_attributes(attrs: &[ast::Attribute], fld: &MacroExpander) {
@@ -59,9 +93,7 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             // Assert that we drop any macro attributes on the floor here
             drop(attrs);
 
-            let expanded_expr = match expand_mac_invoc(mac, span,
-                                                       |r| r.make_expr(),
-                                                       mark_expr, fld) {
+            let expanded_expr = match expand_mac_invoc(mac, span, fld) {
                 Some(expr) => expr,
                 None => {
                     return DummyResult::raw_expr(span);
@@ -182,19 +214,9 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
     });
 }
 
-/// Expand a (not-ident-style) macro invocation. Returns the result
-/// of expansion and the mark which must be applied to the result.
-/// Our current interface doesn't allow us to apply the mark to the
-/// result until after calling make_expr, make_items, etc.
-fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
-                             span: codemap::Span,
-                             parse_thunk: F,
-                             mark_thunk: G,
-                             fld: &mut MacroExpander)
-                             -> Option<T> where
-    F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
-    G: FnOnce(T, Mrk) -> T,
-{
+/// Expand a (not-ident-style) macro invocation. Returns the result of expansion.
+fn expand_mac_invoc<T: MacroGenerable>(mac: ast::Mac, span: Span, fld: &mut MacroExpander)
+                                       -> Option<T> {
     // it would almost certainly be cleaner to pass the whole
     // macro invocation in, rather than pulling it apart and
     // marking the tts and the ctxt separately. This also goes
@@ -245,7 +267,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
                     let expanded = expandfun.expand(fld.cx,
                                                     mac_span,
                                                     &marked_before[..]);
-                    parse_thunk(expanded)
+                    T::make_with(expanded)
                 };
                 let parsed = match opt_parsed {
                     Some(e) => e,
@@ -258,7 +280,7 @@ fn expand_mac_invoc<T, F, G>(mac: ast::Mac,
                         return None;
                     }
                 };
-                Some(mark_thunk(parsed,fm))
+                Some(parsed.fold_with(&mut Marker { mark: fm }))
             }
             _ => {
                 fld.cx.span_err(
@@ -523,11 +545,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
     // Assert that we drop any macro attributes on the floor here
     drop(attrs);
 
-    let maybe_new_items =
-        expand_mac_invoc(mac.unwrap(), stmt.span,
-                         |r| r.make_stmts(),
-                         |stmts, mark| stmts.move_map(|m| mark_stmt(m, mark)),
-                         fld);
+    let maybe_new_items: Option<SmallVector<ast::Stmt>> =
+        expand_mac_invoc(mac.unwrap(), stmt.span, fld);
 
     let mut fully_expanded = match maybe_new_items {
         Some(stmts) => {
@@ -759,6 +778,7 @@ fn expand_pat(p: P<ast::Pat>, fld: &mut MacroExpander) -> P<ast::Pat> {
             PatKind::Mac(mac) => (mac.node.path, mac.node.tts),
             _ => unreachable!()
         };
+
         if pth.segments.len() > 1 {
             fld.cx.span_err(pth.span, "expected macro name without module separators");
             return DummyResult::raw_pat(span);
@@ -1079,11 +1099,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
         ast::ImplItemKind::Macro(mac) => {
             check_attributes(&ii.attrs, fld);
 
-            let maybe_new_items =
-                expand_mac_invoc(mac, ii.span,
-                                 |r| r.make_impl_items(),
-                                 |meths, mark| meths.move_map(|m| mark_impl_item(m, mark)),
-                                 fld);
+            let maybe_new_items: Option<SmallVector<ast::ImplItem>> =
+                expand_mac_invoc(mac, ii.span, fld);
 
             match maybe_new_items {
                 Some(impl_items) => {
@@ -1139,10 +1156,7 @@ pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
     let t = match t.node.clone() {
         ast::TyKind::Mac(mac) => {
             if fld.cx.ecfg.features.unwrap().type_macros {
-                let expanded_ty = match expand_mac_invoc(mac, t.span,
-                                                         |r| r.make_ty(),
-                                                         mark_ty,
-                                                         fld) {
+                let expanded_ty = match expand_mac_invoc(mac, t.span, fld) {
                     Some(ty) => ty,
                     None => {
                         return DummyResult::raw_ty(t.span);
@@ -1426,38 +1440,17 @@ fn mark_tts(tts: &[TokenTree], m: Mrk) -> Vec<TokenTree> {
     noop_fold_tts(tts, &mut Marker{mark:m})
 }
 
-// apply a given mark to the given expr. Used following the expansion of a macro.
-fn mark_expr(expr: P<ast::Expr>, m: Mrk) -> P<ast::Expr> {
-    Marker{mark:m}.fold_expr(expr)
-}
-
 // apply a given mark to the given pattern. Used following the expansion of a macro.
 fn mark_pat(pat: P<ast::Pat>, m: Mrk) -> P<ast::Pat> {
     Marker{mark:m}.fold_pat(pat)
 }
 
-// apply a given mark to the given stmt. Used following the expansion of a macro.
-fn mark_stmt(stmt: ast::Stmt, m: Mrk) -> ast::Stmt {
-    Marker{mark:m}.fold_stmt(stmt)
-        .expect_one("marking a stmt didn't return exactly one stmt")
-}
-
 // apply a given mark to the given item. Used following the expansion of a macro.
 fn mark_item(expr: P<ast::Item>, m: Mrk) -> P<ast::Item> {
     Marker{mark:m}.fold_item(expr)
         .expect_one("marking an item didn't return exactly one item")
 }
 
-// apply a given mark to the given item. Used following the expansion of a macro.
-fn mark_impl_item(ii: ast::ImplItem, m: Mrk) -> ast::ImplItem {
-    Marker{mark:m}.fold_impl_item(ii)
-        .expect_one("marking an impl item didn't return exactly one impl item")
-}
-
-fn mark_ty(ty: P<ast::Ty>, m: Mrk) -> P<ast::Ty> {
-    Marker { mark: m }.fold_ty(ty)
-}
-
 /// Check that there are no macro invocations left in the AST:
 pub fn check_for_macros(sess: &parse::ParseSess, krate: &ast::Crate) {
     visit::walk_crate(&mut MacroExterminator{sess:sess}, krate);