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
#![feature(plugin_registrar, quote, rustc_private)]
extern crate rustc_plugin;
extern crate syntax;
use rustc_plugin::registry::Registry;
use syntax::ast::{Expr, ExprKind, Item, ItemKind, LitKind, Mac, MetaItem, MetaItemKind};
use syntax::codemap::Span;
use syntax::fold::{self, Folder};
use syntax::ptr::P;
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::parse::token;
const ATTR_NAME: &'static str = "overload_strings";
struct StrFolder<'a, 'cx: 'a>(&'a mut ExtCtxt<'cx>, Option<Span>);
impl<'a, 'cx> Folder for StrFolder<'a, 'cx> {
fn fold_item_simple(&mut self, i: Item) -> Item {
if i.attrs.iter().any(|attr| {
match attr.node.value.node {
MetaItemKind::Word(ref name) if name == ATTR_NAME => true,
_ => false
}
}) { return i; }
match i.node {
ItemKind::Static(..) | ItemKind::Const(..) => {
i
}
ItemKind::Mod(_) => {
if let Some(top_span) = self.1 {
if i.span == top_span {
return fold::noop_fold_item_simple(i, self);
}
}
i
}
_ => fold::noop_fold_item_simple(i, self)
}
}
fn fold_expr(&mut self, e: P<Expr>) -> P<Expr> {
if let ExprKind::Lit(ref l) = e.node {
if let LitKind::Str(..) = l.node {
return quote_expr!(self.0, $e.into());
}
}
e.map(|e| fold::noop_fold_expr(e, self))
}
fn fold_mac(&mut self, mac: Mac) -> Mac {
fold::noop_fold_mac(mac, self)
}
}
pub fn insert_str_into(cx: &mut ExtCtxt, _span: Span, _mi: &MetaItem,
a: Annotatable) -> Annotatable {
match a {
Annotatable::Item(i) => Annotatable::Item(
StrFolder(cx, Some(i.span)).fold_item(i).expect_one("expected one item")),
Annotatable::TraitItem(i) => Annotatable::TraitItem(
i.map(|i| StrFolder(cx, None).fold_trait_item(i).expect_one("expected one item"))),
Annotatable::ImplItem(i) => Annotatable::ImplItem(
i.map(|i| StrFolder(cx, None).fold_impl_item(i).expect_one("expected one item"))),
}
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
reg.register_syntax_extension(token::intern(ATTR_NAME),
SyntaxExtension::MultiModifier(Box::new(insert_str_into)));
}