]> git.lizzy.rs Git - rust.git/blob - src/libproc_macro/lib.rs
Rollup merge of #40129 - abonander:proc_macro_bang, r=jseyfried
[rust.git] / src / libproc_macro / lib.rs
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 //! A support library for macro authors when defining new macros.
12 //!
13 //! This library, provided by the standard distribution, provides the types
14 //! consumed in the interfaces of procedurally defined macro definitions.
15 //! Currently the primary use of this crate is to provide the ability to define
16 //! new custom derive modes through `#[proc_macro_derive]`.
17 //!
18 //! Note that this crate is intentionally very bare-bones currently. The main
19 //! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
20 //! implementations, indicating that it can only go to and come from a string.
21 //! This functionality is intended to be expanded over time as more surface
22 //! area for macro authors is stabilized.
23 //!
24 //! See [the book](../../book/procedural-macros.html) for more.
25
26 #![crate_name = "proc_macro"]
27 #![stable(feature = "proc_macro_lib", since = "1.15.0")]
28 #![crate_type = "rlib"]
29 #![crate_type = "dylib"]
30 #![deny(warnings)]
31 #![deny(missing_docs)]
32
33 #![feature(rustc_private)]
34 #![feature(staged_api)]
35 #![feature(lang_items)]
36
37 extern crate syntax;
38
39 use std::fmt;
40 use std::str::FromStr;
41
42 use syntax::errors::DiagnosticBuilder;
43 use syntax::parse;
44 use syntax::tokenstream::TokenStream as TokenStream_;
45
46 /// The main type provided by this crate, representing an abstract stream of
47 /// tokens.
48 ///
49 /// This is both the input and output of `#[proc_macro_derive]` definitions.
50 /// Currently it's required to be a list of valid Rust items, but this
51 /// restriction may be lifted in the future.
52 ///
53 /// The API of this type is intentionally bare-bones, but it'll be expanded over
54 /// time!
55 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
56 pub struct TokenStream {
57     inner: TokenStream_,
58 }
59
60 /// Error returned from `TokenStream::from_str`.
61 #[derive(Debug)]
62 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
63 pub struct LexError {
64     _inner: (),
65 }
66
67 /// Permanently unstable internal implementation details of this crate. This
68 /// should not be used.
69 ///
70 /// These methods are used by the rest of the compiler to generate instances of
71 /// `TokenStream` to hand to macro definitions, as well as consume the output.
72 ///
73 /// Note that this module is also intentionally separate from the rest of the
74 /// crate. This allows the `#[unstable]` directive below to naturally apply to
75 /// all of the contents.
76 #[unstable(feature = "proc_macro_internals", issue = "27812")]
77 #[doc(hidden)]
78 pub mod __internal {
79     use std::cell::Cell;
80     use std::rc::Rc;
81
82     use syntax::ast;
83     use syntax::ptr::P;
84     use syntax::parse::{self, token, ParseSess};
85     use syntax::tokenstream::{TokenTree, TokenStream as TokenStream_};
86
87     use super::{TokenStream, LexError};
88
89     pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
90         TokenStream {
91             inner: TokenTree::Token(item.span, token::Interpolated(Rc::new(token::NtItem(item))))
92                 .into()
93         }
94     }
95
96     pub fn token_stream_wrap(inner: TokenStream_) -> TokenStream {
97         TokenStream {
98             inner: inner
99         }
100     }
101
102     pub fn token_stream_parse_items(stream: TokenStream) -> Result<Vec<P<ast::Item>>, LexError> {
103         with_parse_sess(move |sess| {
104             let mut parser = parse::new_parser_from_ts(sess, stream.inner);
105             let mut items = Vec::new();
106
107             while let Some(item) = try!(parser.parse_item().map_err(super::parse_to_lex_err)) {
108                 items.push(item)
109             }
110
111             Ok(items)
112         })
113     }
114
115     pub fn token_stream_inner(stream: TokenStream) -> TokenStream_ {
116         stream.inner
117     }
118
119     pub trait Registry {
120         fn register_custom_derive(&mut self,
121                                   trait_name: &str,
122                                   expand: fn(TokenStream) -> TokenStream,
123                                   attributes: &[&'static str]);
124
125         fn register_attr_proc_macro(&mut self,
126                                     name: &str,
127                                     expand: fn(TokenStream, TokenStream) -> TokenStream);
128
129         fn register_bang_proc_macro(&mut self,
130                                     name: &str,
131                                     expand: fn(TokenStream) -> TokenStream);
132     }
133
134     // Emulate scoped_thread_local!() here essentially
135     thread_local! {
136         static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _);
137     }
138
139     pub fn set_parse_sess<F, R>(sess: &ParseSess, f: F) -> R
140         where F: FnOnce() -> R
141     {
142         struct Reset { prev: *const ParseSess }
143
144         impl Drop for Reset {
145             fn drop(&mut self) {
146                 CURRENT_SESS.with(|p| p.set(self.prev));
147             }
148         }
149
150         CURRENT_SESS.with(|p| {
151             let _reset = Reset { prev: p.get() };
152             p.set(sess);
153             f()
154         })
155     }
156
157     pub fn with_parse_sess<F, R>(f: F) -> R
158         where F: FnOnce(&ParseSess) -> R
159     {
160         let p = CURRENT_SESS.with(|p| p.get());
161         assert!(!p.is_null(), "proc_macro::__internal::with_parse_sess() called \
162                                before set_parse_sess()!");
163         f(unsafe { &*p })
164     }
165 }
166
167 fn parse_to_lex_err(mut err: DiagnosticBuilder) -> LexError {
168     err.cancel();
169     LexError { _inner: () }
170 }
171
172 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
173 impl FromStr for TokenStream {
174     type Err = LexError;
175
176     fn from_str(src: &str) -> Result<TokenStream, LexError> {
177         __internal::with_parse_sess(|sess| {
178             let src = src.to_string();
179             let name = "<proc-macro source code>".to_string();
180             let tts = parse::parse_tts_from_source_str(name, src, sess);
181
182             Ok(__internal::token_stream_wrap(tts.into_iter().collect()))
183         })
184     }
185 }
186
187 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
188 impl fmt::Display for TokenStream {
189     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
190         self.inner.fmt(f)
191     }
192 }