]> git.proxmox.com Git - rustc.git/blobdiff - src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / test / run-pass-fulldeps / auxiliary / macro_crate_test.rs
index 3f50811f826e07e83a37bd50d8b0fbfac40fc665..4885863122c3bd86d969a18bb75ff868d5c17fcf 100644 (file)
@@ -10,6 +10,7 @@
 
 // force-host
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(plugin_registrar, quote, rustc_private)]
 
 extern crate syntax;
@@ -17,8 +18,10 @@ extern crate rustc;
 extern crate rustc_plugin;
 extern crate syntax_pos;
 
-use syntax::ast::{self, Item, MetaItem, ImplItem, TraitItem, ItemKind};
+use syntax::ast::{self, Item, MetaItem, ItemKind};
+use syntax::codemap::DUMMY_SP;
 use syntax::ext::base::*;
+use syntax::ext::quote::rt::ToTokens;
 use syntax::parse::{self, token};
 use syntax::ptr::P;
 use syntax::tokenstream::TokenTree;
@@ -41,10 +44,13 @@ pub fn plugin_registrar(reg: &mut Registry) {
         token::intern("duplicate"),
         // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
         MultiDecorator(Box::new(expand_duplicate)));
+    reg.register_syntax_extension(
+        token::intern("caller"),
+        // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
+        MultiDecorator(Box::new(expand_caller)));
 }
 
-fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
-                   -> Box<MacResult+'static> {
+fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
     if !tts.is_empty() {
         cx.span_fatal(sp, "make_a_1 takes no arguments");
     }
@@ -52,19 +58,18 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
 }
 
 // See Issue #15750
-fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree])
-                   -> Box<MacResult+'static> {
+fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
     // Parse an expression and emit it unchanged.
-    let mut parser = parse::new_parser_from_tts(cx.parse_sess(),
-        cx.cfg(), tts.to_vec());
+    let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec());
     let expr = parser.parse_expr().unwrap();
     MacEager::expr(quote_expr!(&mut *cx, $expr))
 }
 
 fn expand_into_foo_multi(cx: &mut ExtCtxt,
-                         sp: Span,
-                         attr: &MetaItem,
-                         it: Annotatable) -> Vec<Annotatable> {
+                         _sp: Span,
+                         _attr: &MetaItem,
+                         it: Annotatable)
+                         -> Vec<Annotatable> {
     match it {
         Annotatable::Item(it) => vec![
             Annotatable::Item(P(Item {
@@ -74,20 +79,20 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
             Annotatable::Item(quote_item!(cx, enum Foo3 { Bar }).unwrap()),
             Annotatable::Item(quote_item!(cx, #[cfg(any())] fn foo2() {}).unwrap()),
         ],
-        Annotatable::ImplItem(it) => vec![
+        Annotatable::ImplItem(_it) => vec![
             quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
                 match i.node {
-                    ItemKind::Impl(_, _, _, _, _, mut items) => {
+                    ItemKind::Impl(.., mut items) => {
                         Annotatable::ImplItem(P(items.pop().expect("impl method not found")))
                     }
                     _ => unreachable!("impl parsed to something other than impl")
                 }
             })
         ],
-        Annotatable::TraitItem(it) => vec![
+        Annotatable::TraitItem(_it) => vec![
             quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
                 match i.node {
-                    ItemKind::Trait(_, _, _, mut items) => {
+                    ItemKind::Trait(.., mut items) => {
                         Annotatable::TraitItem(P(items.pop().expect("trait method not found")))
                     }
                     _ => unreachable!("trait parsed to something other than trait")
@@ -99,15 +104,14 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
 
 // Create a duplicate of the annotatable, based on the MetaItem
 fn expand_duplicate(cx: &mut ExtCtxt,
-                    sp: Span,
+                    _sp: Span,
                     mi: &MetaItem,
                     it: &Annotatable,
-                    push: &mut FnMut(Annotatable))
-{
+                    push: &mut FnMut(Annotatable)) {
     let copy_name = match mi.node {
         ast::MetaItemKind::List(_, ref xs) => {
-            if let ast::MetaItemKind::Word(ref w) = xs[0].node {
-                token::str_to_ident(&w)
+            if let Some(word) = xs[0].word() {
+                token::str_to_ident(&word.name())
             } else {
                 cx.span_err(mi.span, "Expected word");
                 return;
@@ -142,4 +146,69 @@ fn expand_duplicate(cx: &mut ExtCtxt,
     }
 }
 
+pub fn token_separate<T: ToTokens>(ecx: &ExtCtxt, things: &[T],
+                                   token: token::Token) -> Vec<TokenTree> {
+    let mut output: Vec<TokenTree> = vec![];
+    for (i, thing) in things.iter().enumerate() {
+        output.extend(thing.to_tokens(ecx));
+        if i < things.len() - 1 {
+            output.push(TokenTree::Token(DUMMY_SP, token.clone()));
+        }
+    }
+
+    output
+}
+
+fn expand_caller(cx: &mut ExtCtxt,
+                 sp: Span,
+                 mi: &MetaItem,
+                 it: &Annotatable,
+                 push: &mut FnMut(Annotatable)) {
+    let (orig_fn_name, ret_type) = match *it {
+        Annotatable::Item(ref item) => match item.node {
+            ItemKind::Fn(ref decl, ..) => {
+                (item.ident, &decl.output)
+            }
+            _ => cx.span_fatal(item.span, "Only functions with return types can be annotated.")
+        },
+        _ => cx.span_fatal(sp, "Only functions can be annotated.")
+    };
+
+    let (caller_name, arguments) = if let Some(list) = mi.meta_item_list() {
+        if list.len() < 2 {
+            cx.span_fatal(mi.span(), "Need a function name and at least one parameter.");
+        }
+
+        let fn_name = match list[0].name() {
+            Some(name) => token::str_to_ident(&name),
+            None => cx.span_fatal(list[0].span(), "First parameter must be an ident.")
+        };
+
+        (fn_name, &list[1..])
+    } else {
+        cx.span_fatal(mi.span, "Expected list.");
+    };
+
+    let literals: Vec<ast::Lit> = arguments.iter().map(|arg| {
+        if let Some(lit) = arg.literal() {
+            lit.clone()
+        } else {
+            cx.span_fatal(arg.span(), "Expected literal.");
+        }
+    }).collect();
+
+    let arguments = token_separate(cx, literals.as_slice(), token::Comma);
+    if let ast::FunctionRetTy::Ty(ref rt) = *ret_type {
+        push(Annotatable::Item(quote_item!(cx,
+                                           fn $caller_name() -> $rt {
+                                               $orig_fn_name($arguments)
+                                           }).unwrap()))
+    } else {
+        push(Annotatable::Item(quote_item!(cx,
+                                           fn $caller_name() {
+                                               $orig_fn_name($arguments)
+                                           }).unwrap()))
+    }
+}
+
 pub fn foo() {}