]> git.proxmox.com Git - rustc.git/blame - src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / test / run-pass-fulldeps / auxiliary / macro_crate_test.rs
CommitLineData
85aaf69f 1// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
1a4d82fc
JJ
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
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.
10
11// force-host
12
d9579d0f 13#![feature(plugin_registrar, quote, rustc_private)]
1a4d82fc
JJ
14
15extern crate syntax;
16extern crate rustc;
92a42be0 17extern crate rustc_plugin;
3157f602 18extern crate syntax_pos;
1a4d82fc 19
9e0c209e
SL
20use syntax::ast::{self, Item, MetaItem, ItemKind};
21use syntax::codemap::DUMMY_SP;
1a4d82fc 22use syntax::ext::base::*;
9e0c209e 23use syntax::ext::quote::rt::ToTokens;
d9579d0f 24use syntax::parse::{self, token};
1a4d82fc 25use syntax::ptr::P;
3157f602
XL
26use syntax::tokenstream::TokenTree;
27use syntax_pos::Span;
92a42be0 28use rustc_plugin::Registry;
1a4d82fc
JJ
29
30#[macro_export]
85aaf69f 31macro_rules! exported_macro { () => (2) }
85aaf69f 32macro_rules! unexported_macro { () => (3) }
1a4d82fc
JJ
33
34#[plugin_registrar]
35pub fn plugin_registrar(reg: &mut Registry) {
36 reg.register_macro("make_a_1", expand_make_a_1);
1a4d82fc 37 reg.register_macro("identity", expand_identity);
85aaf69f
SL
38 reg.register_syntax_extension(
39 token::intern("into_multi_foo"),
c34b1796
AL
40 // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
41 MultiModifier(Box::new(expand_into_foo_multi)));
d9579d0f
AL
42 reg.register_syntax_extension(
43 token::intern("duplicate"),
44 // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
45 MultiDecorator(Box::new(expand_duplicate)));
9e0c209e
SL
46 reg.register_syntax_extension(
47 token::intern("caller"),
48 // FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
49 MultiDecorator(Box::new(expand_caller)));
1a4d82fc
JJ
50}
51
9e0c209e 52fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
1a4d82fc
JJ
53 if !tts.is_empty() {
54 cx.span_fatal(sp, "make_a_1 takes no arguments");
55 }
c34b1796 56 MacEager::expr(quote_expr!(cx, 1))
1a4d82fc
JJ
57}
58
59// See Issue #15750
9e0c209e 60fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
1a4d82fc 61 // Parse an expression and emit it unchanged.
c30ab7b3 62 let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.to_vec());
92a42be0 63 let expr = parser.parse_expr().unwrap();
c34b1796 64 MacEager::expr(quote_expr!(&mut *cx, $expr))
1a4d82fc
JJ
65}
66
85aaf69f 67fn expand_into_foo_multi(cx: &mut ExtCtxt,
9e0c209e
SL
68 _sp: Span,
69 _attr: &MetaItem,
70 it: Annotatable)
71 -> Vec<Annotatable> {
85aaf69f 72 match it {
3157f602 73 Annotatable::Item(it) => vec![
85aaf69f
SL
74 Annotatable::Item(P(Item {
75 attrs: it.attrs.clone(),
76 ..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone()
3157f602
XL
77 })),
78 Annotatable::Item(quote_item!(cx, enum Foo3 { Bar }).unwrap()),
5bcae85e 79 Annotatable::Item(quote_item!(cx, #[cfg(any())] fn foo2() {}).unwrap()),
3157f602 80 ],
9e0c209e 81 Annotatable::ImplItem(_it) => vec![
c34b1796
AL
82 quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
83 match i.node {
9e0c209e 84 ItemKind::Impl(.., mut items) => {
7453a54e 85 Annotatable::ImplItem(P(items.pop().expect("impl method not found")))
c34b1796
AL
86 }
87 _ => unreachable!("impl parsed to something other than impl")
88 }
89 })
3157f602 90 ],
9e0c209e 91 Annotatable::TraitItem(_it) => vec![
c34b1796
AL
92 quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
93 match i.node {
9e0c209e 94 ItemKind::Trait(.., mut items) => {
7453a54e 95 Annotatable::TraitItem(P(items.pop().expect("trait method not found")))
c34b1796
AL
96 }
97 _ => unreachable!("trait parsed to something other than trait")
98 }
99 })
3157f602 100 ],
85aaf69f
SL
101 }
102}
103
d9579d0f
AL
104// Create a duplicate of the annotatable, based on the MetaItem
105fn expand_duplicate(cx: &mut ExtCtxt,
9e0c209e 106 _sp: Span,
d9579d0f 107 mi: &MetaItem,
62682a34 108 it: &Annotatable,
9e0c209e 109 push: &mut FnMut(Annotatable)) {
d9579d0f 110 let copy_name = match mi.node {
7453a54e 111 ast::MetaItemKind::List(_, ref xs) => {
9e0c209e
SL
112 if let Some(word) = xs[0].word() {
113 token::str_to_ident(&word.name())
d9579d0f
AL
114 } else {
115 cx.span_err(mi.span, "Expected word");
116 return;
117 }
118 }
119 _ => {
120 cx.span_err(mi.span, "Expected list");
121 return;
122 }
123 };
1a4d82fc 124
d9579d0f
AL
125 // Duplicate the item but replace its ident by the MetaItem
126 match it.clone() {
127 Annotatable::Item(it) => {
128 let mut new_it = (*it).clone();
129 new_it.attrs.clear();
130 new_it.ident = copy_name;
131 push(Annotatable::Item(P(new_it)));
132 }
133 Annotatable::ImplItem(it) => {
134 let mut new_it = (*it).clone();
135 new_it.attrs.clear();
136 new_it.ident = copy_name;
137 push(Annotatable::ImplItem(P(new_it)));
138 }
139 Annotatable::TraitItem(tt) => {
140 let mut new_it = (*tt).clone();
141 new_it.attrs.clear();
142 new_it.ident = copy_name;
143 push(Annotatable::TraitItem(P(new_it)));
144 }
1a4d82fc 145 }
1a4d82fc
JJ
146}
147
9e0c209e
SL
148pub fn token_separate<T: ToTokens>(ecx: &ExtCtxt, things: &[T],
149 token: token::Token) -> Vec<TokenTree> {
150 let mut output: Vec<TokenTree> = vec![];
151 for (i, thing) in things.iter().enumerate() {
152 output.extend(thing.to_tokens(ecx));
153 if i < things.len() - 1 {
154 output.push(TokenTree::Token(DUMMY_SP, token.clone()));
155 }
156 }
157
158 output
159}
160
161fn expand_caller(cx: &mut ExtCtxt,
162 sp: Span,
163 mi: &MetaItem,
164 it: &Annotatable,
165 push: &mut FnMut(Annotatable)) {
166 let (orig_fn_name, ret_type) = match *it {
167 Annotatable::Item(ref item) => match item.node {
168 ItemKind::Fn(ref decl, ..) => {
169 (item.ident, &decl.output)
170 }
171 _ => cx.span_fatal(item.span, "Only functions with return types can be annotated.")
172 },
173 _ => cx.span_fatal(sp, "Only functions can be annotated.")
174 };
175
176 let (caller_name, arguments) = if let Some(list) = mi.meta_item_list() {
177 if list.len() < 2 {
178 cx.span_fatal(mi.span(), "Need a function name and at least one parameter.");
179 }
180
181 let fn_name = match list[0].name() {
182 Some(name) => token::str_to_ident(&name),
183 None => cx.span_fatal(list[0].span(), "First parameter must be an ident.")
184 };
185
186 (fn_name, &list[1..])
187 } else {
188 cx.span_fatal(mi.span, "Expected list.");
189 };
190
191 let literals: Vec<ast::Lit> = arguments.iter().map(|arg| {
192 if let Some(lit) = arg.literal() {
193 lit.clone()
194 } else {
195 cx.span_fatal(arg.span(), "Expected literal.");
196 }
197 }).collect();
198
199 let arguments = token_separate(cx, literals.as_slice(), token::Comma);
200 if let ast::FunctionRetTy::Ty(ref rt) = *ret_type {
201 push(Annotatable::Item(quote_item!(cx,
202 fn $caller_name() -> $rt {
203 $orig_fn_name($arguments)
204 }).unwrap()))
205 } else {
206 push(Annotatable::Item(quote_item!(cx,
207 fn $caller_name() {
208 $orig_fn_name($arguments)
209 }).unwrap()))
210 }
211}
212
1a4d82fc 213pub fn foo() {}