Skip to content

Commit 6004171

Browse files
committed
Allow syntax extensions which modify and decorate
This adds a new SyntaxExtension type - Renovator. A renovator is a syntax extension which can modify *and* decorate the items it is attached to - the union of `MultiModifier` and `MultiDecorator`. This allows things such as syntax extensions which modify existing methods for types, and implement traits all in one.
1 parent 368f6ae commit 6004171

File tree

5 files changed

+110
-28
lines changed

5 files changed

+110
-28
lines changed

src/librustc_plugin/registry.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc::session::Session;
1616
use rustc::mir::transform::MirMapPass;
1717

1818
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
19-
use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator};
19+
use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator, Renovator};
2020
use syntax::ext::base::{MacroExpanderFn, MacroRulesTT};
2121
use syntax::codemap::Span;
2222
use syntax::parse::token;
@@ -112,6 +112,7 @@ impl<'a> Registry<'a> {
112112
}
113113
MultiDecorator(ext) => MultiDecorator(ext),
114114
MultiModifier(ext) => MultiModifier(ext),
115+
Renovator(ext) => Renovator(ext),
115116
MacroRulesTT => {
116117
self.sess.err("plugin tried to register a new MacroRulesTT");
117118
return;

src/libsyntax/ext/base.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,33 @@ impl<F> MultiItemModifier for F
149149
}
150150
}
151151

152+
pub trait ItemRenovator {
153+
fn expand(&self,
154+
ecx: &mut ExtCtxt,
155+
span: Span,
156+
meta_item: &ast::MetaItem,
157+
item: Annotatable,
158+
push: &mut FnMut(Annotatable))
159+
-> Annotatable;
160+
}
161+
162+
impl<F> ItemRenovator for F
163+
where F : Fn(&mut ExtCtxt,
164+
Span,
165+
&ast::MetaItem,
166+
Annotatable,
167+
&mut FnMut(Annotatable)) -> Annotatable
168+
{
169+
fn expand(&self,
170+
ecx: &mut ExtCtxt,
171+
sp: Span,
172+
meta_item: &ast::MetaItem,
173+
item: Annotatable,
174+
push: &mut FnMut(Annotatable)) -> Annotatable {
175+
(*self)(ecx, sp, meta_item, item, push)
176+
}
177+
}
178+
152179
/// Represents a thing that maps token trees to Macro Results
153180
pub trait TTMacroExpander {
154181
fn expand<'cx>(&self,
@@ -419,6 +446,12 @@ pub enum SyntaxExtension {
419446
/// in-place. More flexible version than Modifier.
420447
MultiModifier(Box<MultiItemModifier + 'static>),
421448

449+
/// A syntax extension that is attached to an item, modifying it in
450+
/// place *and* creating new items based upon it.
451+
///
452+
/// It can be thought of as the union of `MultiDecorator` and `MultiModifier`.
453+
Renovator(Box<ItemRenovator + 'static>),
454+
422455
/// A normal, function-like syntax extension.
423456
///
424457
/// `bytes!` is a `NormalTT`.

src/libsyntax/ext/expand.rs

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ fn expand_annotatable(a: Annotatable,
725725

726726
let mut decorator_items = SmallVector::zero();
727727
let mut new_attrs = Vec::new();
728-
expand_decorators(a.clone(), fld, &mut decorator_items, &mut new_attrs);
728+
let a = expand_renovators_and_decorators(a, fld, &mut decorator_items, &mut new_attrs);
729729

730730
let mut new_items: SmallVector<Annotatable> = match a {
731731
Annotatable::Item(it) => match it.node {
@@ -816,47 +816,63 @@ macro_rules! partition {
816816
partition!(multi_modifiers, MultiModifier);
817817

818818

819-
fn expand_decorators(a: Annotatable,
820-
fld: &mut MacroExpander,
821-
decorator_items: &mut SmallVector<Annotatable>,
822-
new_attrs: &mut Vec<ast::Attribute>)
819+
fn expand_renovators_and_decorators(mut item: Annotatable,
820+
fld: &mut MacroExpander,
821+
decorator_items: &mut SmallVector<Annotatable>,
822+
new_attrs: &mut Vec<ast::Attribute>) -> Annotatable
823823
{
824-
for attr in a.attrs() {
824+
let attrs: Vec<_> = item.attrs().iter().cloned().collect();
825+
826+
for attr in attrs {
825827
let mname = intern(&attr.name());
828+
829+
fld.cx.bt_push(ExpnInfo {
830+
call_site: attr.span,
831+
callee: NameAndSpan {
832+
format: MacroAttribute(mname),
833+
span: Some(attr.span),
834+
// attributes can do whatever they like,
835+
// for now.
836+
allow_internal_unstable: true,
837+
}
838+
});
839+
840+
// we'd ideally decorator_items.push_all(expand_annotatable(ann, fld)),
841+
// but that double-mut-borrows fld
842+
let mut items: SmallVector<Annotatable> = SmallVector::zero();
843+
826844
match fld.cx.syntax_env.find(mname) {
827845
Some(rc) => match *rc {
828846
MultiDecorator(ref dec) => {
829847
attr::mark_used(&attr);
830848

831-
fld.cx.bt_push(ExpnInfo {
832-
call_site: attr.span,
833-
callee: NameAndSpan {
834-
format: MacroAttribute(mname),
835-
span: Some(attr.span),
836-
// attributes can do whatever they like,
837-
// for now.
838-
allow_internal_unstable: true,
839-
}
840-
});
841-
842-
// we'd ideally decorator_items.push_all(expand_annotatable(ann, fld)),
843-
// but that double-mut-borrows fld
844-
let mut items: SmallVector<Annotatable> = SmallVector::zero();
845849
dec.expand(fld.cx,
846850
attr.span,
847851
&attr.node.value,
848-
&a,
852+
&item,
849853
&mut |ann| items.push(ann));
850-
decorator_items.extend(items.into_iter()
851-
.flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
854+
},
855+
Renovator(ref ren) => {
856+
attr::mark_used(&attr);
852857

853-
fld.cx.bt_pop();
854-
}
855-
_ => new_attrs.push((*attr).clone()),
858+
item = ren.expand(fld.cx,
859+
attr.span,
860+
&attr.node.value,
861+
item,
862+
&mut |ann| items.push(ann));
863+
},
864+
_ => new_attrs.push(attr),
856865
},
857-
_ => new_attrs.push((*attr).clone()),
866+
_ => new_attrs.push(attr),
858867
}
868+
869+
decorator_items.extend(items.into_iter()
870+
.flat_map(|ann| expand_annotatable(ann, fld).into_iter()));
871+
872+
fld.cx.bt_pop();
859873
}
874+
875+
item
860876
}
861877

862878
fn expand_item_multi_modifier(mut it: Annotatable,

src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ pub fn plugin_registrar(reg: &mut Registry) {
3939
token::intern("duplicate"),
4040
// FIXME (#22405): Replace `Box::new` with `box` here when/if possible.
4141
MultiDecorator(Box::new(expand_duplicate)));
42+
reg.register_syntax_extension(
43+
token::intern("wrap"),
44+
Renovator(Box::new(expand_wrap)));
4245
}
4346

4447
fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
@@ -138,4 +141,25 @@ fn expand_duplicate(cx: &mut ExtCtxt,
138141
}
139142
}
140143

144+
fn expand_wrap(cx: &mut ExtCtxt,
145+
sp: Span,
146+
meta_item: &MetaItem,
147+
mut item: Annotatable,
148+
push: &mut FnMut(Annotatable)) -> Annotatable
149+
{
150+
151+
match item {
152+
Annotatable::Item(item) => {
153+
push(Annotatable::Item(item.clone()));
154+
155+
Annotatable::Item(P(Item {
156+
attrs: item.attrs.clone(),
157+
..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone()
158+
}))
159+
},
160+
_ => item,
161+
}
162+
}
163+
141164
pub fn foo() {}
165+
pub fn main() { }

src/test/run-pass-fulldeps/macro-crate.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ impl Qux for i32 {
3333

3434
impl Qux for u8 {}
3535

36+
#[wrap]
37+
struct Bar;
38+
39+
impl Bar
40+
{
41+
fn new() -> Self { Bar }
42+
}
43+
3644
pub fn main() {
3745
assert_eq!(1, make_a_1!());
3846
assert_eq!(2, exported_macro!());

0 commit comments

Comments
 (0)