about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-06-25 22:05:08 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-06-25 22:35:01 +0000
commitf0310e061b9d0a7d8dc515390fa68dfb6318df4b (patch)
tree09633b17c39077a6128e2a7a34d86f7daffcfbab /src/libsyntax
parentb8214dc6c6fc20d0a660fb5700dca9ebf51ebe89 (diff)
parentdc3d878e0f513bde3dfad69d4f2722e2884c23a3 (diff)
downloadrust-f0310e061b9d0a7d8dc515390fa68dfb6318df4b.tar.gz
rust-f0310e061b9d0a7d8dc515390fa68dfb6318df4b.zip
Rollup merge of #34213 - josephDunne:trait_item_macros, r=jseyfried
**syntax-[breaking-change]** cc #31645
New `TraitItemKind::Macro` variant

This change adds support for macro expansion inside trait items by adding the new `TraitItemKind::Macro` and associated parsing code.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs1
-rw-r--r--src/libsyntax/ext/base.rs18
-rw-r--r--src/libsyntax/ext/expand.rs53
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs15
-rw-r--r--src/libsyntax/fold.rs3
-rw-r--r--src/libsyntax/parse/parser.rs158
-rw-r--r--src/libsyntax/print/pprust.rs11
-rw-r--r--src/libsyntax/visit.rs3
8 files changed, 175 insertions, 87 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index c3cc84b7701..64680ff4d8a 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1430,6 +1430,7 @@ pub enum TraitItemKind {
     Const(P<Ty>, Option<P<Expr>>),
     Method(MethodSig, Option<P<Block>>),
     Type(TyParamBounds, Option<P<Ty>>),
+    Macro(Mac),
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index f2a005573d5..9d467b4095a 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -241,6 +241,11 @@ pub trait MacResult {
         None
     }
 
+    /// Create zero or more trait items.
+    fn make_trait_items(self: Box<Self>) -> Option<SmallVector<ast::TraitItem>> {
+        None
+    }
+
     /// Create a pattern.
     fn make_pat(self: Box<Self>) -> Option<P<ast::Pat>> {
         None
@@ -288,6 +293,7 @@ make_MacEager! {
     pat: P<ast::Pat>,
     items: SmallVector<P<ast::Item>>,
     impl_items: SmallVector<ast::ImplItem>,
+    trait_items: SmallVector<ast::TraitItem>,
     stmts: SmallVector<ast::Stmt>,
     ty: P<ast::Ty>,
 }
@@ -305,6 +311,10 @@ impl MacResult for MacEager {
         self.impl_items
     }
 
+    fn make_trait_items(self: Box<Self>) -> Option<SmallVector<ast::TraitItem>> {
+        self.trait_items
+    }
+
     fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
         match self.stmts.as_ref().map_or(0, |s| s.len()) {
             0 => make_stmts_default!(self),
@@ -413,6 +423,14 @@ impl MacResult for DummyResult {
         }
     }
 
+    fn make_trait_items(self: Box<DummyResult>) -> Option<SmallVector<ast::TraitItem>> {
+        if self.expr_only {
+            None
+        } else {
+            Some(SmallVector::zero())
+        }
+    }
+
     fn make_stmts(self: Box<DummyResult>) -> Option<SmallVector<ast::Stmt>> {
         Some(SmallVector::one(
             codemap::respan(self.span,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 5beb4937207..126f39bcb0e 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -81,8 +81,11 @@ impl_macro_generable! {
         "statement",  .make_stmts, lift .fold_stmt, lift .visit_stmt, |_span| SmallVector::zero();
     SmallVector<P<ast::Item>>:
         "item",       .make_items, lift .fold_item, lift .visit_item, |_span| SmallVector::zero();
+    SmallVector<ast::TraitItem>:
+        "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item,
+        |_span| SmallVector::zero();
     SmallVector<ast::ImplItem>:
-        "impl item",  .make_impl_items, lift .fold_impl_item, lift .visit_impl_item,
+        "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item,
         |_span| SmallVector::zero();
 }
 
@@ -754,25 +757,10 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
             _ => noop_fold_item(it, fld),
         }.into_iter().map(|i| Annotatable::Item(i)).collect(),
 
-        Annotatable::TraitItem(it) => match it.node {
-            ast::TraitItemKind::Method(_, Some(_)) => {
-                let ti = it.unwrap();
-                SmallVector::one(ast::TraitItem {
-                    id: ti.id,
-                    ident: ti.ident,
-                    attrs: ti.attrs,
-                    node: match ti.node  {
-                        ast::TraitItemKind::Method(sig, Some(body)) => {
-                            let (sig, body) = expand_and_rename_method(sig, body, fld);
-                            ast::TraitItemKind::Method(sig, Some(body))
-                        }
-                        _ => unreachable!()
-                    },
-                    span: ti.span,
-                })
-            }
-            _ => fold::noop_fold_trait_item(it.unwrap(), fld)
-        }.into_iter().map(|ti| Annotatable::TraitItem(P(ti))).collect(),
+        Annotatable::TraitItem(it) => {
+            expand_trait_item(it.unwrap(), fld).into_iter().
+                map(|it| Annotatable::TraitItem(P(it))).collect()
+        }
 
         Annotatable::ImplItem(ii) => {
             expand_impl_item(ii.unwrap(), fld).into_iter().
@@ -900,6 +888,31 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
     }
 }
 
+fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
+                     -> SmallVector<ast::TraitItem> {
+    match ti.node {
+        ast::TraitItemKind::Method(_, Some(_)) => {
+            SmallVector::one(ast::TraitItem {
+                id: ti.id,
+                ident: ti.ident,
+                attrs: ti.attrs,
+                node: match ti.node  {
+                    ast::TraitItemKind::Method(sig, Some(body)) => {
+                        let (sig, body) = expand_and_rename_method(sig, body, fld);
+                        ast::TraitItemKind::Method(sig, Some(body))
+                    }
+                    _ => unreachable!()
+                },
+                span: ti.span,
+            })
+        }
+        ast::TraitItemKind::Macro(mac) => {
+            expand_mac_invoc(mac, None, ti.attrs, ti.span, fld)
+        }
+        _ => fold::noop_fold_trait_item(ti, fld)
+    }
+}
+
 /// Given a fn_decl and a block and a MacroExpander, expand the fn_decl, then use the
 /// PatIdents in its arguments to perform renaming in the FnDecl and
 /// the block, returning both the new FnDecl and the new Block.
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index bbe989b0f40..fe98394c3e4 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -100,6 +100,21 @@ impl<'a> MacResult for ParserAnyMacro<'a> {
         Some(ret)
     }
 
+    fn make_trait_items(self: Box<ParserAnyMacro<'a>>)
+                       -> Option<SmallVector<ast::TraitItem>> {
+        let mut ret = SmallVector::zero();
+        loop {
+            let mut parser = self.parser.borrow_mut();
+            match parser.token {
+                token::Eof => break,
+                _ => ret.push(panictry!(parser.parse_trait_item()))
+            }
+        }
+        self.ensure_complete_parse(false, "item");
+        Some(ret)
+    }
+
+
     fn make_stmts(self: Box<ParserAnyMacro<'a>>)
                  -> Option<SmallVector<ast::Stmt>> {
         let mut ret = SmallVector::zero();
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index edf418e3332..c44d5f368fe 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -945,6 +945,9 @@ pub fn noop_fold_trait_item<T: Folder>(i: TraitItem, folder: &mut T)
                 TraitItemKind::Type(folder.fold_bounds(bounds),
                               default.map(|x| folder.fold_ty(x)))
             }
+            ast::TraitItemKind::Macro(mac) => {
+                TraitItemKind::Macro(folder.fold_mac(mac))
+            }
         },
         span: folder.new_span(i.span)
     })
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 341b076e7cf..fafe16192f0 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1232,55 +1232,70 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse the items in a trait declaration
-    pub fn parse_trait_items(&mut self) -> PResult<'a,  Vec<TraitItem>> {
-        self.parse_unspanned_seq(
-            &token::OpenDelim(token::Brace),
-            &token::CloseDelim(token::Brace),
-            SeqSep::none(),
-            |p| -> PResult<'a, TraitItem> {
-            maybe_whole!(no_clone_from_p p, NtTraitItem);
-            let mut attrs = p.parse_outer_attributes()?;
-            let lo = p.span.lo;
-
-            let (name, node) = if p.eat_keyword(keywords::Type) {
-                let TyParam {ident, bounds, default, ..} = p.parse_ty_param()?;
-                p.expect(&token::Semi)?;
-                (ident, TraitItemKind::Type(bounds, default))
-            } else if p.is_const_item() {
-                p.expect_keyword(keywords::Const)?;
-                let ident = p.parse_ident()?;
-                p.expect(&token::Colon)?;
-                let ty = p.parse_ty_sum()?;
-                let default = if p.check(&token::Eq) {
-                    p.bump();
-                    let expr = p.parse_expr()?;
-                    p.commit_expr_expecting(&expr, token::Semi)?;
-                    Some(expr)
-                } else {
-                    p.expect(&token::Semi)?;
-                    None
-                };
-                (ident, TraitItemKind::Const(ty, default))
+    pub fn parse_trait_item(&mut self) -> PResult<'a, TraitItem> {
+        maybe_whole!(no_clone_from_p self, NtTraitItem);
+        let mut attrs = self.parse_outer_attributes()?;
+        let lo = self.span.lo;
+
+        let (name, node) = if self.eat_keyword(keywords::Type) {
+            let TyParam {ident, bounds, default, ..} = self.parse_ty_param()?;
+            self.expect(&token::Semi)?;
+            (ident, TraitItemKind::Type(bounds, default))
+        } else if self.is_const_item() {
+                self.expect_keyword(keywords::Const)?;
+            let ident = self.parse_ident()?;
+            self.expect(&token::Colon)?;
+            let ty = self.parse_ty_sum()?;
+            let default = if self.check(&token::Eq) {
+                self.bump();
+                let expr = self.parse_expr()?;
+                self.commit_expr_expecting(&expr, token::Semi)?;
+                Some(expr)
+            } else {
+                self.expect(&token::Semi)?;
+                None
+            };
+            (ident, TraitItemKind::Const(ty, default))
+        } else if !self.token.is_any_keyword()
+            && self.look_ahead(1, |t| *t == token::Not)
+            && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren))
+                || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) {
+                // trait item macro.
+                // code copied from parse_macro_use_or_failure... abstraction!
+                let lo = self.span.lo;
+                let pth = self.parse_ident_into_path()?;
+                self.expect(&token::Not)?;
+
+                // eat a matched-delimiter token tree:
+                let delim = self.expect_open_delim()?;
+                let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
+                                             SeqSep::none(),
+                                             |pp| pp.parse_token_tree())?;
+                let m_ = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT };
+                let m: ast::Mac = codemap::Spanned { node: m_,
+                                                     span: mk_sp(lo,
+                                                                 self.last_span.hi) };
+                if delim != token::Brace {
+                    self.expect(&token::Semi)?
+                }
+                (keywords::Invalid.ident(), ast::TraitItemKind::Macro(m))
             } else {
-                let (constness, unsafety, abi) = match p.parse_fn_front_matter() {
+                let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
                     Ok(cua) => cua,
                     Err(e) => {
                         loop {
-                            match p.token {
+                            match self.token {
                                 token::Eof => break,
-
                                 token::CloseDelim(token::Brace) |
                                 token::Semi => {
-                                    p.bump();
+                                    self.bump();
                                     break;
                                 }
-
                                 token::OpenDelim(token::Brace) => {
-                                    p.parse_token_tree()?;
+                                    self.parse_token_tree()?;
                                     break;
                                 }
-
-                                _ => p.bump()
+                                _ => self.bump()
                             }
                         }
 
@@ -1288,17 +1303,17 @@ impl<'a> Parser<'a> {
                     }
                 };
 
-                let ident = p.parse_ident()?;
-                let mut generics = p.parse_generics()?;
+                let ident = self.parse_ident()?;
+                let mut generics = self.parse_generics()?;
 
-                let d = p.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
+                let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>|{
                     // This is somewhat dubious; We don't want to allow
                     // argument names to be left off if there is a
                     // definition...
                     p.parse_arg_general(false)
                 })?;
 
-                generics.where_clause = p.parse_where_clause()?;
+                generics.where_clause = self.parse_where_clause()?;
                 let sig = ast::MethodSig {
                     unsafety: unsafety,
                     constness: constness,
@@ -1307,37 +1322,47 @@ impl<'a> Parser<'a> {
                     abi: abi,
                 };
 
-                let body = match p.token {
-                  token::Semi => {
-                    p.bump();
-                    debug!("parse_trait_methods(): parsing required method");
-                    None
-                  }
-                  token::OpenDelim(token::Brace) => {
-                    debug!("parse_trait_methods(): parsing provided method");
-                    let (inner_attrs, body) =
-                        p.parse_inner_attrs_and_block()?;
-                    attrs.extend(inner_attrs.iter().cloned());
-                    Some(body)
-                  }
+                let body = match self.token {
+                    token::Semi => {
+                        self.bump();
+                        debug!("parse_trait_methods(): parsing required method");
+                        None
+                    }
+                    token::OpenDelim(token::Brace) => {
+                        debug!("parse_trait_methods(): parsing provided method");
+                        let (inner_attrs, body) =
+                            self.parse_inner_attrs_and_block()?;
+                        attrs.extend(inner_attrs.iter().cloned());
+                        Some(body)
+                    }
 
-                  _ => {
-                      let token_str = p.this_token_to_string();
-                      return Err(p.fatal(&format!("expected `;` or `{{`, found `{}`",
-                                       token_str)[..]))
-                  }
+                    _ => {
+                        let token_str = self.this_token_to_string();
+                        return Err(self.fatal(&format!("expected `;` or `{{`, found `{}`",
+                                                    token_str)[..]))
+                    }
                 };
                 (ident, ast::TraitItemKind::Method(sig, body))
             };
+        Ok(TraitItem {
+            id: ast::DUMMY_NODE_ID,
+            ident: name,
+            attrs: attrs,
+            node: node,
+            span: mk_sp(lo, self.last_span.hi),
+        })
+    }
 
-            Ok(TraitItem {
-                id: ast::DUMMY_NODE_ID,
-                ident: name,
-                attrs: attrs,
-                node: node,
-                span: mk_sp(lo, p.last_span.hi),
+
+    /// Parse the items in a trait declaration
+    pub fn parse_trait_items(&mut self) -> PResult<'a,  Vec<TraitItem>> {
+        self.parse_unspanned_seq(
+            &token::OpenDelim(token::Brace),
+            &token::CloseDelim(token::Brace),
+            SeqSep::none(),
+            |p| -> PResult<'a, TraitItem> {
+                p.parse_trait_item()
             })
-        })
     }
 
     /// Parse a possibly mutable type
@@ -4940,7 +4965,6 @@ impl<'a> Parser<'a> {
 
     /// Parse trait Foo { ... }
     fn parse_item_trait(&mut self, unsafety: Unsafety) -> PResult<'a, ItemInfo> {
-
         let ident = self.parse_ident()?;
         let mut tps = self.parse_generics()?;
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index a2ee5bf6090..fb1c9679c8f 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -1550,6 +1550,17 @@ impl<'a> State<'a> {
                 try!(self.print_associated_type(ti.ident, Some(bounds),
                                            default.as_ref().map(|ty| &**ty)));
             }
+            ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => {
+                // code copied from ItemKind::Mac:
+                self.print_path(&node.path, false, 0)?;
+                word(&mut self.s, "! ")?;
+                self.cbox(INDENT_UNIT)?;
+                self.popen()?;
+                self.print_tts(&node.tts[..])?;
+                self.pclose()?;
+                word(&mut self.s, ";")?;
+                self.end()?
+            }
         }
         self.ann.post(self, NodeSubItem(ti.id))
     }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 07a6317706b..db911fc667b 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -568,6 +568,9 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
             walk_list!(visitor, visit_ty_param_bound, bounds);
             walk_list!(visitor, visit_ty, default);
         }
+        TraitItemKind::Macro(ref mac) => {
+            visitor.visit_mac(mac);
+        }
     }
 }