]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ext/proc_macro.rs
Rename `Stmt.node` to `Stmt.kind`
[rust.git] / src / libsyntax / ext / proc_macro.rs
1 use crate::ast::{self, ItemKind, Attribute, Mac};
2 use crate::attr::{mark_used, mark_known};
3 use crate::errors::{Applicability, FatalError};
4 use crate::ext::base::{self, *};
5 use crate::ext::proc_macro_server;
6 use crate::parse::{self, token};
7 use crate::parse::parser::PathStyle;
8 use crate::symbol::sym;
9 use crate::tokenstream::{self, TokenStream};
10 use crate::visit::Visitor;
11
12 use rustc_data_structures::sync::Lrc;
13 use syntax_pos::{Span, DUMMY_SP};
14
15 const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
16     proc_macro::bridge::server::SameThread;
17
18 pub struct BangProcMacro {
19     pub client: proc_macro::bridge::client::Client<
20         fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
21     >,
22 }
23
24 impl base::ProcMacro for BangProcMacro {
25     fn expand<'cx>(&self,
26                    ecx: &'cx mut ExtCtxt<'_>,
27                    span: Span,
28                    input: TokenStream)
29                    -> TokenStream {
30         let server = proc_macro_server::Rustc::new(ecx);
31         match self.client.run(&EXEC_STRATEGY, server, input) {
32             Ok(stream) => stream,
33             Err(e) => {
34                 let msg = "proc macro panicked";
35                 let mut err = ecx.struct_span_fatal(span, msg);
36                 if let Some(s) = e.as_str() {
37                     err.help(&format!("message: {}", s));
38                 }
39
40                 err.emit();
41                 FatalError.raise();
42             }
43         }
44     }
45 }
46
47 pub struct AttrProcMacro {
48     pub client: proc_macro::bridge::client::Client<
49         fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
50     >,
51 }
52
53 impl base::AttrProcMacro for AttrProcMacro {
54     fn expand<'cx>(&self,
55                    ecx: &'cx mut ExtCtxt<'_>,
56                    span: Span,
57                    annotation: TokenStream,
58                    annotated: TokenStream)
59                    -> TokenStream {
60         let server = proc_macro_server::Rustc::new(ecx);
61         match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
62             Ok(stream) => stream,
63             Err(e) => {
64                 let msg = "custom attribute panicked";
65                 let mut err = ecx.struct_span_fatal(span, msg);
66                 if let Some(s) = e.as_str() {
67                     err.help(&format!("message: {}", s));
68                 }
69
70                 err.emit();
71                 FatalError.raise();
72             }
73         }
74     }
75 }
76
77 pub struct ProcMacroDerive {
78     pub client: proc_macro::bridge::client::Client<
79         fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
80     >,
81 }
82
83 impl MultiItemModifier for ProcMacroDerive {
84     fn expand(&self,
85               ecx: &mut ExtCtxt<'_>,
86               span: Span,
87               _meta_item: &ast::MetaItem,
88               item: Annotatable)
89               -> Vec<Annotatable> {
90         let item = match item {
91             Annotatable::Arm(..) |
92             Annotatable::Field(..) |
93             Annotatable::FieldPat(..) |
94             Annotatable::GenericParam(..) |
95             Annotatable::Param(..) |
96             Annotatable::StructField(..) |
97             Annotatable::Variant(..)
98                 => panic!("unexpected annotatable"),
99             Annotatable::Item(item) => item,
100             Annotatable::ImplItem(_) |
101             Annotatable::TraitItem(_) |
102             Annotatable::ForeignItem(_) |
103             Annotatable::Stmt(_) |
104             Annotatable::Expr(_) => {
105                 ecx.span_err(span, "proc-macro derives may only be \
106                                     applied to a struct, enum, or union");
107                 return Vec::new()
108             }
109         };
110         match item.node {
111             ItemKind::Struct(..) |
112             ItemKind::Enum(..) |
113             ItemKind::Union(..) => {},
114             _ => {
115                 ecx.span_err(span, "proc-macro derives may only be \
116                                     applied to a struct, enum, or union");
117                 return Vec::new()
118             }
119         }
120
121         let token = token::Interpolated(Lrc::new(token::NtItem(item)));
122         let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
123
124         let server = proc_macro_server::Rustc::new(ecx);
125         let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
126             Ok(stream) => stream,
127             Err(e) => {
128                 let msg = "proc-macro derive panicked";
129                 let mut err = ecx.struct_span_fatal(span, msg);
130                 if let Some(s) = e.as_str() {
131                     err.help(&format!("message: {}", s));
132                 }
133
134                 err.emit();
135                 FatalError.raise();
136             }
137         };
138
139         let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
140         let msg = "proc-macro derive produced unparseable tokens";
141
142         let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
143         let mut items = vec![];
144
145         loop {
146             match parser.parse_item() {
147                 Ok(None) => break,
148                 Ok(Some(item)) => {
149                     items.push(Annotatable::Item(item))
150                 }
151                 Err(mut err) => {
152                     // FIXME: handle this better
153                     err.cancel();
154                     ecx.struct_span_fatal(span, msg).emit();
155                     FatalError.raise();
156                 }
157             }
158         }
159
160
161         // fail if there have been errors emitted
162         if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
163             ecx.struct_span_fatal(span, msg).emit();
164             FatalError.raise();
165         }
166
167         items
168     }
169 }
170
171 crate struct MarkAttrs<'a>(crate &'a [ast::Name]);
172
173 impl<'a> Visitor<'a> for MarkAttrs<'a> {
174     fn visit_attribute(&mut self, attr: &Attribute) {
175         if let Some(ident) = attr.ident() {
176             if self.0.contains(&ident.name) {
177                 mark_used(attr);
178                 mark_known(attr);
179             }
180         }
181     }
182
183     fn visit_mac(&mut self, _mac: &Mac) {}
184 }
185
186 pub fn is_proc_macro_attr(attr: &Attribute) -> bool {
187     [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
188         .iter().any(|kind| attr.check_name(*kind))
189 }
190
191 crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
192     let mut result = Vec::new();
193     attrs.retain(|attr| {
194         if attr.path != sym::derive {
195             return true;
196         }
197         if !attr.is_meta_item_list() {
198             cx.struct_span_err(attr.span, "malformed `derive` attribute input")
199                 .span_suggestion(
200                     attr.span,
201                     "missing traits to be derived",
202                     "#[derive(Trait1, Trait2, ...)]".to_owned(),
203                     Applicability::HasPlaceholders,
204                 ).emit();
205             return false;
206         }
207
208         match attr.parse_list(cx.parse_sess,
209                               |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
210             Ok(traits) => {
211                 result.extend(traits);
212                 true
213             }
214             Err(mut e) => {
215                 e.emit();
216                 false
217             }
218         }
219     });
220     result
221 }