1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
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.
13 use errors::FatalError;
14 use proc_macro::{TokenStream, __internal};
15 use syntax::ast::{self, ItemKind, Attribute, Mac};
16 use syntax::attr::{mark_used, mark_known};
17 use syntax::codemap::Span;
18 use syntax::ext::base::*;
19 use syntax::visit::Visitor;
21 struct MarkAttrs<'a>(&'a [ast::Name]);
23 impl<'a> Visitor<'a> for MarkAttrs<'a> {
24 fn visit_attribute(&mut self, attr: &Attribute) {
25 if let Some(name) = attr.name() {
26 if self.0.contains(&name) {
33 fn visit_mac(&mut self, _mac: &Mac) {}
36 pub struct ProcMacroDerive {
37 inner: fn(TokenStream) -> TokenStream,
38 attrs: Vec<ast::Name>,
41 impl ProcMacroDerive {
42 pub fn new(inner: fn(TokenStream) -> TokenStream, attrs: Vec<ast::Name>) -> ProcMacroDerive {
43 ProcMacroDerive { inner: inner, attrs: attrs }
47 impl MultiItemModifier for ProcMacroDerive {
51 _meta_item: &ast::MetaItem,
54 let item = match item {
55 Annotatable::Item(item) => item,
56 Annotatable::ImplItem(_) |
57 Annotatable::TraitItem(_) => {
58 ecx.span_err(span, "proc-macro derives may only be \
59 applied to struct/enum items");
64 ItemKind::Struct(..) |
65 ItemKind::Enum(..) => {},
67 ecx.span_err(span, "proc-macro derives may only be \
68 applied to struct/enum items");
73 // Mark attributes as known, and used.
74 MarkAttrs(&self.attrs).visit_item(&item);
76 let input = __internal::new_token_stream(ecx.resolver.eliminate_crate_var(item.clone()));
77 let res = __internal::set_sess(ecx, || {
78 let inner = self.inner;
79 panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input)))
82 let stream = match res {
85 let msg = "proc-macro derive panicked";
86 let mut err = ecx.struct_span_fatal(span, msg);
87 if let Some(s) = e.downcast_ref::<String>() {
88 err.help(&format!("message: {}", s));
90 if let Some(s) = e.downcast_ref::<&'static str>() {
91 err.help(&format!("message: {}", s));
99 __internal::set_sess(ecx, || {
100 match __internal::token_stream_parse_items(stream) {
101 Ok(new_items) => new_items.into_iter().map(Annotatable::Item).collect(),
103 // FIXME: handle this better
104 let msg = "proc-macro derive produced unparseable tokens";
105 ecx.struct_span_fatal(span, msg).emit();