]>
Commit | Line | Data |
---|---|---|
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 | |
15 | extern crate syntax; | |
16 | extern crate rustc; | |
92a42be0 | 17 | extern crate rustc_plugin; |
1a4d82fc | 18 | |
7453a54e | 19 | use syntax::ast::{self, TokenTree, Item, MetaItem, ImplItem, TraitItem, ItemKind}; |
1a4d82fc JJ |
20 | use syntax::codemap::Span; |
21 | use syntax::ext::base::*; | |
d9579d0f | 22 | use syntax::parse::{self, token}; |
1a4d82fc | 23 | use syntax::ptr::P; |
92a42be0 | 24 | use rustc_plugin::Registry; |
1a4d82fc JJ |
25 | |
26 | #[macro_export] | |
85aaf69f | 27 | macro_rules! exported_macro { () => (2) } |
85aaf69f | 28 | macro_rules! unexported_macro { () => (3) } |
1a4d82fc JJ |
29 | |
30 | #[plugin_registrar] | |
31 | pub fn plugin_registrar(reg: &mut Registry) { | |
32 | reg.register_macro("make_a_1", expand_make_a_1); | |
1a4d82fc | 33 | reg.register_macro("identity", expand_identity); |
85aaf69f SL |
34 | reg.register_syntax_extension( |
35 | token::intern("into_multi_foo"), | |
c34b1796 AL |
36 | // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. |
37 | MultiModifier(Box::new(expand_into_foo_multi))); | |
d9579d0f AL |
38 | reg.register_syntax_extension( |
39 | token::intern("duplicate"), | |
40 | // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. | |
41 | MultiDecorator(Box::new(expand_duplicate))); | |
1a4d82fc JJ |
42 | } |
43 | ||
44 | fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) | |
45 | -> Box<MacResult+'static> { | |
46 | if !tts.is_empty() { | |
47 | cx.span_fatal(sp, "make_a_1 takes no arguments"); | |
48 | } | |
c34b1796 | 49 | MacEager::expr(quote_expr!(cx, 1)) |
1a4d82fc JJ |
50 | } |
51 | ||
52 | // See Issue #15750 | |
53 | fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) | |
54 | -> Box<MacResult+'static> { | |
55 | // Parse an expression and emit it unchanged. | |
56 | let mut parser = parse::new_parser_from_tts(cx.parse_sess(), | |
57 | cx.cfg(), tts.to_vec()); | |
92a42be0 | 58 | let expr = parser.parse_expr().unwrap(); |
c34b1796 | 59 | MacEager::expr(quote_expr!(&mut *cx, $expr)) |
1a4d82fc JJ |
60 | } |
61 | ||
85aaf69f SL |
62 | fn expand_into_foo_multi(cx: &mut ExtCtxt, |
63 | sp: Span, | |
64 | attr: &MetaItem, | |
65 | it: Annotatable) -> Annotatable { | |
66 | match it { | |
67 | Annotatable::Item(it) => { | |
68 | Annotatable::Item(P(Item { | |
69 | attrs: it.attrs.clone(), | |
70 | ..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone() | |
71 | })) | |
72 | } | |
73 | Annotatable::ImplItem(it) => { | |
c34b1796 AL |
74 | quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| { |
75 | match i.node { | |
7453a54e SL |
76 | ItemKind::Impl(_, _, _, _, _, mut items) => { |
77 | Annotatable::ImplItem(P(items.pop().expect("impl method not found"))) | |
c34b1796 AL |
78 | } |
79 | _ => unreachable!("impl parsed to something other than impl") | |
80 | } | |
81 | }) | |
85aaf69f SL |
82 | } |
83 | Annotatable::TraitItem(it) => { | |
c34b1796 AL |
84 | quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| { |
85 | match i.node { | |
7453a54e SL |
86 | ItemKind::Trait(_, _, _, mut items) => { |
87 | Annotatable::TraitItem(P(items.pop().expect("trait method not found"))) | |
c34b1796 AL |
88 | } |
89 | _ => unreachable!("trait parsed to something other than trait") | |
90 | } | |
91 | }) | |
85aaf69f SL |
92 | } |
93 | } | |
94 | } | |
95 | ||
d9579d0f AL |
96 | // Create a duplicate of the annotatable, based on the MetaItem |
97 | fn expand_duplicate(cx: &mut ExtCtxt, | |
98 | sp: Span, | |
99 | mi: &MetaItem, | |
62682a34 | 100 | it: &Annotatable, |
d9579d0f AL |
101 | push: &mut FnMut(Annotatable)) |
102 | { | |
103 | let copy_name = match mi.node { | |
7453a54e SL |
104 | ast::MetaItemKind::List(_, ref xs) => { |
105 | if let ast::MetaItemKind::Word(ref w) = xs[0].node { | |
d9579d0f AL |
106 | token::str_to_ident(&w) |
107 | } else { | |
108 | cx.span_err(mi.span, "Expected word"); | |
109 | return; | |
110 | } | |
111 | } | |
112 | _ => { | |
113 | cx.span_err(mi.span, "Expected list"); | |
114 | return; | |
115 | } | |
116 | }; | |
1a4d82fc | 117 | |
d9579d0f AL |
118 | // Duplicate the item but replace its ident by the MetaItem |
119 | match it.clone() { | |
120 | Annotatable::Item(it) => { | |
121 | let mut new_it = (*it).clone(); | |
122 | new_it.attrs.clear(); | |
123 | new_it.ident = copy_name; | |
124 | push(Annotatable::Item(P(new_it))); | |
125 | } | |
126 | Annotatable::ImplItem(it) => { | |
127 | let mut new_it = (*it).clone(); | |
128 | new_it.attrs.clear(); | |
129 | new_it.ident = copy_name; | |
130 | push(Annotatable::ImplItem(P(new_it))); | |
131 | } | |
132 | Annotatable::TraitItem(tt) => { | |
133 | let mut new_it = (*tt).clone(); | |
134 | new_it.attrs.clear(); | |
135 | new_it.ident = copy_name; | |
136 | push(Annotatable::TraitItem(P(new_it))); | |
137 | } | |
1a4d82fc | 138 | } |
1a4d82fc JJ |
139 | } |
140 | ||
141 | pub fn foo() {} |