]> git.proxmox.com Git - rustc.git/blob - src/libproc_macro/lib.rs
New upstream version 1.17.0+dfsg1
[rustc.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 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
33 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
34 html_root_url = "https://doc.rust-lang.org/nightly/",
35 html_playground_url = "https://play.rust-lang.org/",
36 issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
37 test(no_crate_inject, attr(deny(warnings))),
38 test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
39
40 #![feature(rustc_private)]
41 #![feature(staged_api)]
42 #![feature(lang_items)]
43
44 extern crate syntax;
45
46 use std::fmt;
47 use std::str::FromStr;
48
49 use syntax::errors::DiagnosticBuilder;
50 use syntax::parse;
51 use syntax::tokenstream::TokenStream as TokenStream_;
52
53 /// The main type provided by this crate, representing an abstract stream of
54 /// tokens.
55 ///
56 /// This is both the input and output of `#[proc_macro_derive]` definitions.
57 /// Currently it's required to be a list of valid Rust items, but this
58 /// restriction may be lifted in the future.
59 ///
60 /// The API of this type is intentionally bare-bones, but it'll be expanded over
61 /// time!
62 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
63 pub struct TokenStream {
64 inner: TokenStream_,
65 }
66
67 /// Error returned from `TokenStream::from_str`.
68 #[derive(Debug)]
69 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
70 pub struct LexError {
71 _inner: (),
72 }
73
74 /// Permanently unstable internal implementation details of this crate. This
75 /// should not be used.
76 ///
77 /// These methods are used by the rest of the compiler to generate instances of
78 /// `TokenStream` to hand to macro definitions, as well as consume the output.
79 ///
80 /// Note that this module is also intentionally separate from the rest of the
81 /// crate. This allows the `#[unstable]` directive below to naturally apply to
82 /// all of the contents.
83 #[unstable(feature = "proc_macro_internals", issue = "27812")]
84 #[doc(hidden)]
85 pub mod __internal {
86 use std::cell::Cell;
87 use std::rc::Rc;
88
89 use syntax::ast;
90 use syntax::ptr::P;
91 use syntax::parse::{self, token, ParseSess};
92 use syntax::tokenstream::{TokenTree, TokenStream as TokenStream_};
93
94 use super::{TokenStream, LexError};
95
96 pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
97 TokenStream {
98 inner: TokenTree::Token(item.span, token::Interpolated(Rc::new(token::NtItem(item))))
99 .into()
100 }
101 }
102
103 pub fn token_stream_wrap(inner: TokenStream_) -> TokenStream {
104 TokenStream {
105 inner: inner
106 }
107 }
108
109 pub fn token_stream_parse_items(stream: TokenStream) -> Result<Vec<P<ast::Item>>, LexError> {
110 with_parse_sess(move |sess| {
111 let mut parser = parse::stream_to_parser(sess, stream.inner);
112 let mut items = Vec::new();
113
114 while let Some(item) = try!(parser.parse_item().map_err(super::parse_to_lex_err)) {
115 items.push(item)
116 }
117
118 Ok(items)
119 })
120 }
121
122 pub fn token_stream_inner(stream: TokenStream) -> TokenStream_ {
123 stream.inner
124 }
125
126 pub trait Registry {
127 fn register_custom_derive(&mut self,
128 trait_name: &str,
129 expand: fn(TokenStream) -> TokenStream,
130 attributes: &[&'static str]);
131
132 fn register_attr_proc_macro(&mut self,
133 name: &str,
134 expand: fn(TokenStream, TokenStream) -> TokenStream);
135
136 fn register_bang_proc_macro(&mut self,
137 name: &str,
138 expand: fn(TokenStream) -> TokenStream);
139 }
140
141 // Emulate scoped_thread_local!() here essentially
142 thread_local! {
143 static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _);
144 }
145
146 pub fn set_parse_sess<F, R>(sess: &ParseSess, f: F) -> R
147 where F: FnOnce() -> R
148 {
149 struct Reset { prev: *const ParseSess }
150
151 impl Drop for Reset {
152 fn drop(&mut self) {
153 CURRENT_SESS.with(|p| p.set(self.prev));
154 }
155 }
156
157 CURRENT_SESS.with(|p| {
158 let _reset = Reset { prev: p.get() };
159 p.set(sess);
160 f()
161 })
162 }
163
164 pub fn with_parse_sess<F, R>(f: F) -> R
165 where F: FnOnce(&ParseSess) -> R
166 {
167 let p = CURRENT_SESS.with(|p| p.get());
168 assert!(!p.is_null(), "proc_macro::__internal::with_parse_sess() called \
169 before set_parse_sess()!");
170 f(unsafe { &*p })
171 }
172 }
173
174 fn parse_to_lex_err(mut err: DiagnosticBuilder) -> LexError {
175 err.cancel();
176 LexError { _inner: () }
177 }
178
179 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
180 impl FromStr for TokenStream {
181 type Err = LexError;
182
183 fn from_str(src: &str) -> Result<TokenStream, LexError> {
184 __internal::with_parse_sess(|sess| {
185 let src = src.to_string();
186 let name = "<proc-macro source code>".to_string();
187 let stream = parse::parse_stream_from_source_str(name, src, sess);
188 Ok(__internal::token_stream_wrap(stream))
189 })
190 }
191 }
192
193 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
194 impl fmt::Display for TokenStream {
195 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196 self.inner.fmt(f)
197 }
198 }