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