]>
Commit | Line | Data |
---|---|---|
e74abb32 XL |
1 | use crate::base::{self, *}; |
2 | use crate::proc_macro_server; | |
3 | ||
6a06907d | 4 | use rustc_ast as ast; |
fc512014 | 5 | use rustc_ast::ptr::P; |
74b04a01 | 6 | use rustc_ast::token; |
5869c6ff | 7 | use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree}; |
dfeec247 | 8 | use rustc_data_structures::sync::Lrc; |
6a06907d | 9 | use rustc_errors::ErrorReported; |
f035d41b | 10 | use rustc_parse::nt_to_tokenstream; |
5869c6ff | 11 | use rustc_parse::parser::ForceCollect; |
dfeec247 | 12 | use rustc_span::{Span, DUMMY_SP}; |
416331ca | 13 | |
e74abb32 | 14 | const EXEC_STRATEGY: pm::bridge::server::SameThread = pm::bridge::server::SameThread; |
416331ca XL |
15 | |
16 | pub struct BangProcMacro { | |
dfeec247 | 17 | pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>, |
416331ca XL |
18 | } |
19 | ||
20 | impl base::ProcMacro for BangProcMacro { | |
dfeec247 XL |
21 | fn expand<'cx>( |
22 | &self, | |
23 | ecx: &'cx mut ExtCtxt<'_>, | |
24 | span: Span, | |
25 | input: TokenStream, | |
ba9703b0 | 26 | ) -> Result<TokenStream, ErrorReported> { |
416331ca | 27 | let server = proc_macro_server::Rustc::new(ecx); |
1b1a35ee | 28 | self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| { |
ba9703b0 XL |
29 | let mut err = ecx.struct_span_err(span, "proc macro panicked"); |
30 | if let Some(s) = e.as_str() { | |
31 | err.help(&format!("message: {}", s)); | |
416331ca | 32 | } |
ba9703b0 XL |
33 | err.emit(); |
34 | ErrorReported | |
35 | }) | |
416331ca XL |
36 | } |
37 | } | |
38 | ||
39 | pub struct AttrProcMacro { | |
e74abb32 | 40 | pub client: pm::bridge::client::Client<fn(pm::TokenStream, pm::TokenStream) -> pm::TokenStream>, |
416331ca XL |
41 | } |
42 | ||
43 | impl base::AttrProcMacro for AttrProcMacro { | |
dfeec247 XL |
44 | fn expand<'cx>( |
45 | &self, | |
46 | ecx: &'cx mut ExtCtxt<'_>, | |
47 | span: Span, | |
48 | annotation: TokenStream, | |
49 | annotated: TokenStream, | |
ba9703b0 | 50 | ) -> Result<TokenStream, ErrorReported> { |
416331ca | 51 | let server = proc_macro_server::Rustc::new(ecx); |
1b1a35ee XL |
52 | self.client |
53 | .run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace) | |
54 | .map_err(|e| { | |
55 | let mut err = ecx.struct_span_err(span, "custom attribute panicked"); | |
56 | if let Some(s) = e.as_str() { | |
57 | err.help(&format!("message: {}", s)); | |
58 | } | |
59 | err.emit(); | |
60 | ErrorReported | |
61 | }) | |
416331ca XL |
62 | } |
63 | } | |
64 | ||
65 | pub struct ProcMacroDerive { | |
e74abb32 | 66 | pub client: pm::bridge::client::Client<fn(pm::TokenStream) -> pm::TokenStream>, |
416331ca XL |
67 | } |
68 | ||
69 | impl MultiItemModifier for ProcMacroDerive { | |
dfeec247 XL |
70 | fn expand( |
71 | &self, | |
72 | ecx: &mut ExtCtxt<'_>, | |
73 | span: Span, | |
74 | _meta_item: &ast::MetaItem, | |
75 | item: Annotatable, | |
ba9703b0 | 76 | ) -> ExpandResult<Vec<Annotatable>, Annotatable> { |
fc512014 XL |
77 | // We need special handling for statement items |
78 | // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`) | |
79 | let mut is_stmt = false; | |
416331ca | 80 | let item = match item { |
fc512014 XL |
81 | Annotatable::Item(item) => token::NtItem(item), |
82 | Annotatable::Stmt(stmt) => { | |
83 | is_stmt = true; | |
84 | assert!(stmt.is_item()); | |
85 | ||
86 | // A proc macro can't observe the fact that we're passing | |
87 | // them an `NtStmt` - it can only see the underlying tokens | |
88 | // of the wrapped item | |
89 | token::NtStmt(stmt.into_inner()) | |
416331ca | 90 | } |
fc512014 | 91 | _ => unreachable!(), |
416331ca | 92 | }; |
6a06907d XL |
93 | let input = if crate::base::pretty_printing_compatibility_hack(&item, &ecx.sess.parse_sess) |
94 | { | |
f035d41b XL |
95 | TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into() |
96 | } else { | |
cdc7bbd5 | 97 | nt_to_tokenstream(&item, &ecx.sess.parse_sess, CanSynthesizeMissingTokens::No) |
f035d41b | 98 | }; |
416331ca XL |
99 | |
100 | let server = proc_macro_server::Rustc::new(ecx); | |
1b1a35ee XL |
101 | let stream = |
102 | match self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace) { | |
103 | Ok(stream) => stream, | |
104 | Err(e) => { | |
105 | let mut err = ecx.struct_span_err(span, "proc-macro derive panicked"); | |
106 | if let Some(s) = e.as_str() { | |
107 | err.help(&format!("message: {}", s)); | |
108 | } | |
109 | err.emit(); | |
110 | return ExpandResult::Ready(vec![]); | |
416331ca | 111 | } |
1b1a35ee | 112 | }; |
416331ca | 113 | |
3dfed10e | 114 | let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count(); |
dfeec247 | 115 | let mut parser = |
3dfed10e | 116 | rustc_parse::stream_to_parser(&ecx.sess.parse_sess, stream, Some("proc-macro derive")); |
416331ca XL |
117 | let mut items = vec![]; |
118 | ||
119 | loop { | |
5869c6ff | 120 | match parser.parse_item(ForceCollect::No) { |
416331ca | 121 | Ok(None) => break, |
fc512014 XL |
122 | Ok(Some(item)) => { |
123 | if is_stmt { | |
124 | items.push(Annotatable::Stmt(P(ecx.stmt_item(span, item)))); | |
125 | } else { | |
126 | items.push(Annotatable::Item(item)); | |
127 | } | |
128 | } | |
416331ca | 129 | Err(mut err) => { |
ba9703b0 XL |
130 | err.emit(); |
131 | break; | |
416331ca XL |
132 | } |
133 | } | |
134 | } | |
135 | ||
416331ca | 136 | // fail if there have been errors emitted |
3dfed10e | 137 | if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before { |
ba9703b0 | 138 | ecx.struct_span_err(span, "proc-macro derive produced unparseable tokens").emit(); |
416331ca XL |
139 | } |
140 | ||
ba9703b0 | 141 | ExpandResult::Ready(items) |
416331ca XL |
142 | } |
143 | } |