]>
Commit | Line | Data |
---|---|---|
9e0c209e SL |
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. | |
4 | // | |
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. | |
10 | ||
11 | use std::panic; | |
12 | ||
13 | use errors::FatalError; | |
c30ab7b3 | 14 | use proc_macro::{TokenStream, __internal}; |
476ff2be SL |
15 | use syntax::ast::{self, ItemKind, Attribute, Mac}; |
16 | use syntax::attr::{mark_used, mark_known}; | |
17 | use syntax::codemap::Span; | |
9e0c209e | 18 | use syntax::ext::base::*; |
476ff2be SL |
19 | use syntax::visit::Visitor; |
20 | ||
21 | struct MarkAttrs<'a>(&'a [ast::Name]); | |
22 | ||
23 | impl<'a> Visitor<'a> for MarkAttrs<'a> { | |
24 | fn visit_attribute(&mut self, attr: &Attribute) { | |
cc61c64b XL |
25 | if let Some(name) = attr.name() { |
26 | if self.0.contains(&name) { | |
27 | mark_used(attr); | |
28 | mark_known(attr); | |
29 | } | |
476ff2be SL |
30 | } |
31 | } | |
32 | ||
33 | fn visit_mac(&mut self, _mac: &Mac) {} | |
34 | } | |
9e0c209e | 35 | |
8bb4bdeb | 36 | pub struct ProcMacroDerive { |
9e0c209e | 37 | inner: fn(TokenStream) -> TokenStream, |
476ff2be | 38 | attrs: Vec<ast::Name>, |
9e0c209e SL |
39 | } |
40 | ||
8bb4bdeb XL |
41 | impl ProcMacroDerive { |
42 | pub fn new(inner: fn(TokenStream) -> TokenStream, attrs: Vec<ast::Name>) -> ProcMacroDerive { | |
43 | ProcMacroDerive { inner: inner, attrs: attrs } | |
9e0c209e SL |
44 | } |
45 | } | |
46 | ||
8bb4bdeb | 47 | impl MultiItemModifier for ProcMacroDerive { |
9e0c209e SL |
48 | fn expand(&self, |
49 | ecx: &mut ExtCtxt, | |
50 | span: Span, | |
476ff2be | 51 | _meta_item: &ast::MetaItem, |
9e0c209e SL |
52 | item: Annotatable) |
53 | -> Vec<Annotatable> { | |
54 | let item = match item { | |
55 | Annotatable::Item(item) => item, | |
56 | Annotatable::ImplItem(_) | | |
57 | Annotatable::TraitItem(_) => { | |
8bb4bdeb | 58 | ecx.span_err(span, "proc-macro derives may only be \ |
9e0c209e SL |
59 | applied to struct/enum items"); |
60 | return Vec::new() | |
61 | } | |
62 | }; | |
63 | match item.node { | |
64 | ItemKind::Struct(..) | | |
476ff2be | 65 | ItemKind::Enum(..) => {}, |
9e0c209e | 66 | _ => { |
8bb4bdeb | 67 | ecx.span_err(span, "proc-macro derives may only be \ |
9e0c209e SL |
68 | applied to struct/enum items"); |
69 | return Vec::new() | |
70 | } | |
71 | } | |
72 | ||
476ff2be SL |
73 | // Mark attributes as known, and used. |
74 | MarkAttrs(&self.attrs).visit_item(&item); | |
75 | ||
76 | let input = __internal::new_token_stream(ecx.resolver.eliminate_crate_var(item.clone())); | |
041b39d2 | 77 | let res = __internal::set_sess(ecx, || { |
9e0c209e SL |
78 | let inner = self.inner; |
79 | panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input))) | |
80 | }); | |
32a655c1 SL |
81 | |
82 | let stream = match res { | |
83 | Ok(stream) => stream, | |
9e0c209e | 84 | Err(e) => { |
8bb4bdeb | 85 | let msg = "proc-macro derive panicked"; |
9e0c209e SL |
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)); | |
89 | } | |
90 | if let Some(s) = e.downcast_ref::<&'static str>() { | |
91 | err.help(&format!("message: {}", s)); | |
92 | } | |
93 | ||
94 | err.emit(); | |
95 | panic!(FatalError); | |
96 | } | |
97 | }; | |
98 | ||
041b39d2 | 99 | __internal::set_sess(ecx, || { |
32a655c1 | 100 | match __internal::token_stream_parse_items(stream) { |
041b39d2 | 101 | Ok(new_items) => new_items.into_iter().map(Annotatable::Item).collect(), |
32a655c1 SL |
102 | Err(_) => { |
103 | // FIXME: handle this better | |
8bb4bdeb | 104 | let msg = "proc-macro derive produced unparseable tokens"; |
32a655c1 SL |
105 | ecx.struct_span_fatal(span, msg).emit(); |
106 | panic!(FatalError); | |
107 | } | |
108 | } | |
041b39d2 | 109 | }) |
9e0c209e SL |
110 | } |
111 | } |