]> git.proxmox.com Git - rustc.git/blob - src/libproc_macro/lib.rs
New upstream version 1.14.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 //! Added recently as part of [RFC 1681] this crate is currently *unstable* and
19 //! requires the `#![feature(proc_macro_lib)]` directive to use.
20 //!
21 //! [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
22 //!
23 //! Note that this crate is intentionally very bare-bones currently. The main
24 //! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
25 //! implementations, indicating that it can only go to and come from a string.
26 //! This functionality is intended to be expanded over time as more surface
27 //! area for macro authors is stabilized.
28
29 #![crate_name = "proc_macro"]
30 #![unstable(feature = "proc_macro_lib", issue = "27812")]
31 #![crate_type = "rlib"]
32 #![crate_type = "dylib"]
33 #![cfg_attr(not(stage0), deny(warnings))]
34 #![deny(missing_docs)]
35
36 #![feature(rustc_private)]
37 #![feature(staged_api)]
38 #![feature(lang_items)]
39
40 extern crate syntax;
41
42 use std::fmt;
43 use std::str::FromStr;
44
45 use syntax::ast;
46 use syntax::parse;
47 use syntax::ptr::P;
48
49 /// The main type provided by this crate, representing an abstract stream of
50 /// tokens.
51 ///
52 /// This is both the input and output of `#[proc_macro_derive]` definitions.
53 /// Currently it's required to be a list of valid Rust items, but this
54 /// restriction may be lifted in the future.
55 ///
56 /// The API of this type is intentionally bare-bones, but it'll be expanded over
57 /// time!
58 pub struct TokenStream {
59 inner: Vec<P<ast::Item>>,
60 }
61
62 /// Error returned from `TokenStream::from_str`.
63 #[derive(Debug)]
64 pub struct LexError {
65 _inner: (),
66 }
67
68 /// Permanently unstable internal implementation details of this crate. This
69 /// should not be used.
70 ///
71 /// These methods are used by the rest of the compiler to generate instances of
72 /// `TokenStream` to hand to macro definitions, as well as consume the output.
73 ///
74 /// Note that this module is also intentionally separate from the rest of the
75 /// crate. This allows the `#[unstable]` directive below to naturally apply to
76 /// all of the contents.
77 #[unstable(feature = "proc_macro_internals", issue = "27812")]
78 #[doc(hidden)]
79 pub mod __internal {
80 use std::cell::Cell;
81
82 use syntax::ast;
83 use syntax::ptr::P;
84 use syntax::parse::ParseSess;
85 use super::TokenStream;
86
87 pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
88 TokenStream { inner: vec![item] }
89 }
90
91 pub fn token_stream_items(stream: TokenStream) -> Vec<P<ast::Item>> {
92 stream.inner
93 }
94
95 pub trait Registry {
96 fn register_custom_derive(&mut self,
97 trait_name: &str,
98 expand: fn(TokenStream) -> TokenStream);
99 }
100
101 // Emulate scoped_thread_local!() here essentially
102 thread_local! {
103 static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _);
104 }
105
106 pub fn set_parse_sess<F, R>(sess: &ParseSess, f: F) -> R
107 where F: FnOnce() -> R
108 {
109 struct Reset { prev: *const ParseSess }
110
111 impl Drop for Reset {
112 fn drop(&mut self) {
113 CURRENT_SESS.with(|p| p.set(self.prev));
114 }
115 }
116
117 CURRENT_SESS.with(|p| {
118 let _reset = Reset { prev: p.get() };
119 p.set(sess);
120 f()
121 })
122 }
123
124 pub fn with_parse_sess<F, R>(f: F) -> R
125 where F: FnOnce(&ParseSess) -> R
126 {
127 let p = CURRENT_SESS.with(|p| p.get());
128 assert!(!p.is_null());
129 f(unsafe { &*p })
130 }
131 }
132
133 impl FromStr for TokenStream {
134 type Err = LexError;
135
136 fn from_str(src: &str) -> Result<TokenStream, LexError> {
137 __internal::with_parse_sess(|sess| {
138 let src = src.to_string();
139 let name = "<proc-macro source code>".to_string();
140 let mut parser = parse::new_parser_from_source_str(sess, name, src);
141 let mut ret = TokenStream { inner: Vec::new() };
142 loop {
143 match parser.parse_item() {
144 Ok(Some(item)) => ret.inner.push(item),
145 Ok(None) => return Ok(ret),
146 Err(mut err) => {
147 err.cancel();
148 return Err(LexError { _inner: () })
149 }
150 }
151 }
152 })
153 }
154 }
155
156 impl fmt::Display for TokenStream {
157 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158 for item in self.inner.iter() {
159 let item = syntax::print::pprust::item_to_string(item);
160 try!(f.write_str(&item));
161 try!(f.write_str("\n"));
162 }
163 Ok(())
164 }
165 }