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