1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#![feature(box_syntax)]
#![feature(plugin_registrar)]
#![feature(rustc_private)]
#![feature(quote)]
extern crate syntax;
extern crate rustc;
extern crate rustc_plugin;
mod lang;
mod marshall;
mod traits;
mod util;
use rustc_plugin::Registry;
use syntax::ptr::P;
use syntax::ast::{Item, ItemKind, MetaItem, Name, Attribute};
use syntax::ext::base::{ExtCtxt,Annotatable};
use syntax::codemap::Span;
use syntax::ext::base::SyntaxExtension;
use syntax::ext::build::AstBuilder;
use syntax::feature_gate::AttributeType;
use syntax::codemap::DUMMY_SP;
pub fn should_export(attrs: &[Attribute]) -> bool {
attrs.iter().any(|attr| attr.path == "plug")
}
#[plugin_registrar]
pub fn registrar(reg: &mut Registry) {
reg.register_syntax_extension(
Name::intern("pluggable"),
SyntaxExtension::MultiModifier(Box::new(expand_pluggable)),
);
reg.register_attribute("pluggable".into(), AttributeType::Normal);
reg.register_attribute("plug".into(), AttributeType::Whitelisted);
}
fn expand_pluggable_struct(ecx: &mut ExtCtxt, item: &Item) -> Vec<Annotatable> {
let ty = ecx.ty_ident(DUMMY_SP, item.ident);
let mut items = Vec::new();
items.push(traits::implement_pluggable_fields(ecx, &ty, &item));
items.push(traits::implement_pluggable(ecx, &ty));
items
}
fn expand_unknown_item(ecx: &mut ExtCtxt, sp: Span) {
ecx.span_err(sp, "only structs and impls can be pluggable".into());
}
fn expand_pluggable(ecx: &mut ExtCtxt, sp: Span, _meta_item: &MetaItem, item: Annotatable) -> Vec<Annotatable> {
let mut items = Vec::new();
match item {
Annotatable::Item(inner_item) => match inner_item.node.clone() {
ItemKind::Struct(..) => {
items.push(Annotatable::Item(inner_item.clone()));
items.extend(expand_pluggable_struct(ecx, &inner_item))
},
ItemKind::Impl(unsafety,polarity,defaultness,generics,tref, ty, impl_items) => {
let pluggable_impl_items: Vec<_> = impl_items.iter().cloned()
.filter(|impl_item| should_export(&impl_item.attrs))
.collect();
let new_impl_items =
marshall::create_marshalls(ecx, &pluggable_impl_items);
items.push(traits::implement_pluggable_methods(
ecx, &ty, &pluggable_impl_items));
let impl_items = impl_items.into_iter().chain(new_impl_items).collect();
items.push(Annotatable::Item(P(Item {
node: ItemKind::Impl(unsafety, polarity, defaultness, generics, tref, ty, impl_items),
..(*inner_item).clone()
})));
},
_ => {
expand_unknown_item(ecx, sp);
},
},
_ => {
expand_unknown_item(ecx, sp);
},
}
items
}