]> git.proxmox.com Git - rustc.git/blame - src/libsyntax_ext/deriving/custom.rs
New upstream version 1.20.0+dfsg1
[rustc.git] / src / libsyntax_ext / deriving / custom.rs
CommitLineData
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
11use std::panic;
12
13use errors::FatalError;
c30ab7b3 14use proc_macro::{TokenStream, __internal};
476ff2be
SL
15use syntax::ast::{self, ItemKind, Attribute, Mac};
16use syntax::attr::{mark_used, mark_known};
17use syntax::codemap::Span;
9e0c209e 18use syntax::ext::base::*;
476ff2be
SL
19use syntax::visit::Visitor;
20
21struct MarkAttrs<'a>(&'a [ast::Name]);
22
23impl<'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 36pub struct ProcMacroDerive {
9e0c209e 37 inner: fn(TokenStream) -> TokenStream,
476ff2be 38 attrs: Vec<ast::Name>,
9e0c209e
SL
39}
40
8bb4bdeb
XL
41impl 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 47impl 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}