Make builtin derives a SyntaxExtension
This allows builtin derives to be registered and resolved, just like other derive types.
This commit is contained in:
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT};
|
pub use self::SyntaxExtension::{MultiDecorator, MultiModifier, NormalTT, IdentTT};
|
||||||
|
|
||||||
use ast::{self, Attribute, Name, PatKind};
|
use ast::{self, Attribute, Name, PatKind, MetaItem};
|
||||||
use attr::HasAttrs;
|
use attr::HasAttrs;
|
||||||
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
|
use codemap::{self, CodeMap, ExpnInfo, Spanned, respan};
|
||||||
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
|
use syntax_pos::{Span, ExpnId, NO_EXPANSION};
|
||||||
@@ -471,6 +471,9 @@ impl MacResult for DummyResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type BuiltinDeriveFn =
|
||||||
|
for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable));
|
||||||
|
|
||||||
/// An enum representing the different kinds of syntax extensions.
|
/// An enum representing the different kinds of syntax extensions.
|
||||||
pub enum SyntaxExtension {
|
pub enum SyntaxExtension {
|
||||||
/// A syntax extension that is attached to an item and creates new items
|
/// A syntax extension that is attached to an item and creates new items
|
||||||
@@ -508,6 +511,9 @@ pub enum SyntaxExtension {
|
|||||||
IdentTT(Box<IdentMacroExpander>, Option<Span>, bool),
|
IdentTT(Box<IdentMacroExpander>, Option<Span>, bool),
|
||||||
|
|
||||||
CustomDerive(Box<MultiItemModifier>),
|
CustomDerive(Box<MultiItemModifier>),
|
||||||
|
|
||||||
|
/// An attribute-like procedural macro that derives a builtin trait.
|
||||||
|
BuiltinDerive(BuiltinDeriveFn),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
pub type NamedSyntaxExtension = (Name, SyntaxExtension);
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks);
|
let tok_result = mac.expand(self.cx, attr.span, attr_toks, item_toks);
|
||||||
self.parse_expansion(tok_result, kind, name, attr.span)
|
self.parse_expansion(tok_result, kind, name, attr.span)
|
||||||
}
|
}
|
||||||
SyntaxExtension::CustomDerive(_) => {
|
SyntaxExtension::CustomDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
|
||||||
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name));
|
self.cx.span_err(attr.span, &format!("`{}` is a derive mode", name));
|
||||||
kind.dummy(attr.span)
|
kind.dummy(attr.span)
|
||||||
}
|
}
|
||||||
@@ -440,7 +440,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||||||
return kind.dummy(span);
|
return kind.dummy(span);
|
||||||
}
|
}
|
||||||
|
|
||||||
SyntaxExtension::CustomDerive(..) => {
|
SyntaxExtension::CustomDerive(..) | SyntaxExtension::BuiltinDerive(..) => {
|
||||||
self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname));
|
self.cx.span_err(path.span, &format!("`{}` is a derive mode", extname));
|
||||||
return kind.dummy(span);
|
return kind.dummy(span);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt,
|
|||||||
mitem: &MetaItem,
|
mitem: &MetaItem,
|
||||||
item: &Annotatable,
|
item: &Annotatable,
|
||||||
push: &mut FnMut(Annotatable)) {
|
push: &mut FnMut(Annotatable)) {
|
||||||
|
deriving::warn_if_deprecated(cx, span, "Decodable");
|
||||||
expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
|
expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
|
|||||||
mitem: &MetaItem,
|
mitem: &MetaItem,
|
||||||
item: &Annotatable,
|
item: &Annotatable,
|
||||||
push: &mut FnMut(Annotatable)) {
|
push: &mut FnMut(Annotatable)) {
|
||||||
|
deriving::warn_if_deprecated(cx, span, "Encodable");
|
||||||
expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
|
expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,11 @@
|
|||||||
|
|
||||||
//! The compiler code necessary to implement the `#[derive]` extensions.
|
//! The compiler code necessary to implement the `#[derive]` extensions.
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
use syntax::ast::{self, MetaItem};
|
use syntax::ast::{self, MetaItem};
|
||||||
use syntax::attr::HasAttrs;
|
use syntax::attr::HasAttrs;
|
||||||
use syntax::codemap;
|
use syntax::codemap;
|
||||||
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
|
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver};
|
||||||
use syntax::ext::build::AstBuilder;
|
use syntax::ext::build::AstBuilder;
|
||||||
use syntax::feature_gate;
|
use syntax::feature_gate;
|
||||||
use syntax::ptr::P;
|
use syntax::ptr::P;
|
||||||
@@ -292,7 +293,10 @@ pub fn expand_derive(cx: &mut ExtCtxt,
|
|||||||
for titem in traits.iter() {
|
for titem in traits.iter() {
|
||||||
let tname = titem.word().unwrap().name();
|
let tname = titem.word().unwrap().name();
|
||||||
let name = Symbol::intern(&format!("derive({})", tname));
|
let name = Symbol::intern(&format!("derive({})", tname));
|
||||||
|
let tname_cx = ast::Ident::with_empty_ctxt(titem.name().unwrap());
|
||||||
let mitem = cx.meta_word(titem.span, name);
|
let mitem = cx.meta_word(titem.span, name);
|
||||||
|
let path = ast::Path::from_ident(titem.span, tname_cx);
|
||||||
|
let ext = cx.resolver.resolve_macro(cx.current_expansion.mark, &path, false).unwrap();
|
||||||
|
|
||||||
let span = Span {
|
let span = Span {
|
||||||
expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
|
expn_id: cx.codemap().record_expansion(codemap::ExpnInfo {
|
||||||
@@ -306,11 +310,15 @@ pub fn expand_derive(cx: &mut ExtCtxt,
|
|||||||
..titem.span
|
..titem.span
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let SyntaxExtension::BuiltinDerive(ref func) = *ext {
|
||||||
let my_item = Annotatable::Item(item);
|
let my_item = Annotatable::Item(item);
|
||||||
expand_builtin(&tname.as_str(), cx, span, &mitem, &my_item, &mut |a| {
|
func(cx, span, &mitem, &my_item, &mut |a| {
|
||||||
items.push(a);
|
items.push(a)
|
||||||
});
|
});
|
||||||
item = my_item.expect_item();
|
item = my_item.expect_item();
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
items.insert(0, Annotatable::Item(item));
|
items.insert(0, Annotatable::Item(item));
|
||||||
@@ -326,21 +334,13 @@ macro_rules! derive_traits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_builtin(name: &str,
|
pub fn register_builtin_derives(resolver: &mut Resolver) {
|
||||||
ecx: &mut ExtCtxt,
|
|
||||||
span: Span,
|
|
||||||
mitem: &MetaItem,
|
|
||||||
item: &Annotatable,
|
|
||||||
push: &mut FnMut(Annotatable)) {
|
|
||||||
match name {
|
|
||||||
$(
|
$(
|
||||||
$name => {
|
resolver.add_ext(
|
||||||
warn_if_deprecated(ecx, span, $name);
|
ast::Ident::with_empty_ctxt(Symbol::intern($name)),
|
||||||
$func(ecx, span, mitem, item, push);
|
Rc::new(SyntaxExtension::BuiltinDerive($func))
|
||||||
}
|
);
|
||||||
)*
|
)*
|
||||||
_ => panic!("not a builtin derive mode: {}", name),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ use syntax::symbol::Symbol;
|
|||||||
pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
|
pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
|
||||||
user_exts: Vec<NamedSyntaxExtension>,
|
user_exts: Vec<NamedSyntaxExtension>,
|
||||||
enable_quotes: bool) {
|
enable_quotes: bool) {
|
||||||
|
deriving::register_builtin_derives(resolver);
|
||||||
|
|
||||||
let mut register = |name, ext| {
|
let mut register = |name, ext| {
|
||||||
resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
|
resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user