2016-08-04 14:20:01 -05:00
|
|
|
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2016-10-03 11:49:39 -05:00
|
|
|
//! A support library for macro authors when defining new macros.
|
2016-08-04 14:20:01 -05:00
|
|
|
//!
|
2016-10-03 11:49:39 -05:00
|
|
|
//! This library, provided by the standard distribution, provides the types
|
|
|
|
//! consumed in the interfaces of procedurally defined macro definitions.
|
|
|
|
//! Currently the primary use of this crate is to provide the ability to define
|
|
|
|
//! new custom derive modes through `#[proc_macro_derive]`.
|
2016-08-04 14:20:01 -05:00
|
|
|
//!
|
2016-10-03 11:49:39 -05:00
|
|
|
//! Note that this crate is intentionally very bare-bones currently. The main
|
|
|
|
//! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
|
|
|
|
//! implementations, indicating that it can only go to and come from a string.
|
|
|
|
//! This functionality is intended to be expanded over time as more surface
|
|
|
|
//! area for macro authors is stabilized.
|
2017-01-01 19:33:37 -06:00
|
|
|
//!
|
2017-06-12 11:30:08 -05:00
|
|
|
//! See [the book](../book/first-edition/procedural-macros.html) for more.
|
2016-08-04 14:20:01 -05:00
|
|
|
|
|
|
|
#![crate_name = "proc_macro"]
|
2017-01-01 18:14:35 -06:00
|
|
|
#![stable(feature = "proc_macro_lib", since = "1.15.0")]
|
2016-08-04 14:20:01 -05:00
|
|
|
#![crate_type = "rlib"]
|
2016-10-03 11:49:39 -05:00
|
|
|
#![crate_type = "dylib"]
|
2016-12-29 11:47:34 -06:00
|
|
|
#![deny(warnings)]
|
2016-10-03 11:49:39 -05:00
|
|
|
#![deny(missing_docs)]
|
2017-03-11 20:54:43 -06:00
|
|
|
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
|
|
|
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
|
|
|
html_root_url = "https://doc.rust-lang.org/nightly/",
|
|
|
|
html_playground_url = "https://play.rust-lang.org/",
|
|
|
|
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
|
|
|
|
test(no_crate_inject, attr(deny(warnings))),
|
|
|
|
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
|
2016-08-04 14:20:01 -05:00
|
|
|
|
|
|
|
#![feature(rustc_private)]
|
2016-10-03 11:49:39 -05:00
|
|
|
#![feature(staged_api)]
|
|
|
|
#![feature(lang_items)]
|
2016-08-04 14:20:01 -05:00
|
|
|
|
|
|
|
extern crate syntax;
|
|
|
|
|
2016-10-03 11:49:39 -05:00
|
|
|
use std::fmt;
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
2017-01-07 23:04:49 -06:00
|
|
|
use syntax::errors::DiagnosticBuilder;
|
2016-10-03 11:49:39 -05:00
|
|
|
use syntax::parse;
|
2017-03-17 18:23:12 -05:00
|
|
|
use syntax::tokenstream;
|
2016-10-03 11:49:39 -05:00
|
|
|
|
|
|
|
/// The main type provided by this crate, representing an abstract stream of
|
|
|
|
/// tokens.
|
|
|
|
///
|
|
|
|
/// This is both the input and output of `#[proc_macro_derive]` definitions.
|
|
|
|
/// Currently it's required to be a list of valid Rust items, but this
|
|
|
|
/// restriction may be lifted in the future.
|
|
|
|
///
|
|
|
|
/// The API of this type is intentionally bare-bones, but it'll be expanded over
|
|
|
|
/// time!
|
2017-01-01 18:14:35 -06:00
|
|
|
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
2017-03-17 18:23:12 -05:00
|
|
|
pub struct TokenStream(tokenstream::TokenStream);
|
2016-10-03 11:49:39 -05:00
|
|
|
|
|
|
|
/// Error returned from `TokenStream::from_str`.
|
|
|
|
#[derive(Debug)]
|
2017-01-01 18:14:35 -06:00
|
|
|
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
2016-10-03 11:49:39 -05:00
|
|
|
pub struct LexError {
|
|
|
|
_inner: (),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Permanently unstable internal implementation details of this crate. This
|
|
|
|
/// should not be used.
|
|
|
|
///
|
|
|
|
/// These methods are used by the rest of the compiler to generate instances of
|
|
|
|
/// `TokenStream` to hand to macro definitions, as well as consume the output.
|
|
|
|
///
|
|
|
|
/// Note that this module is also intentionally separate from the rest of the
|
|
|
|
/// crate. This allows the `#[unstable]` directive below to naturally apply to
|
|
|
|
/// all of the contents.
|
|
|
|
#[unstable(feature = "proc_macro_internals", issue = "27812")]
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub mod __internal {
|
|
|
|
use std::cell::Cell;
|
2017-01-07 23:04:49 -06:00
|
|
|
use std::rc::Rc;
|
2016-10-03 11:49:39 -05:00
|
|
|
|
|
|
|
use syntax::ast;
|
2017-03-28 00:32:43 -05:00
|
|
|
use syntax::ext::base::ExtCtxt;
|
|
|
|
use syntax::ext::hygiene::Mark;
|
2016-10-03 11:49:39 -05:00
|
|
|
use syntax::ptr::P;
|
2017-01-07 23:04:49 -06:00
|
|
|
use syntax::parse::{self, token, ParseSess};
|
2017-03-17 18:23:12 -05:00
|
|
|
use syntax::tokenstream;
|
2017-01-07 23:04:49 -06:00
|
|
|
|
|
|
|
use super::{TokenStream, LexError};
|
2016-10-03 11:49:39 -05:00
|
|
|
|
|
|
|
pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
|
2017-03-17 18:23:12 -05:00
|
|
|
let (span, token) = (item.span, token::Interpolated(Rc::new(token::NtItem(item))));
|
|
|
|
TokenStream(tokenstream::TokenTree::Token(span, token).into())
|
2017-01-07 23:04:49 -06:00
|
|
|
}
|
|
|
|
|
2017-03-17 18:23:12 -05:00
|
|
|
pub fn token_stream_wrap(inner: tokenstream::TokenStream) -> TokenStream {
|
|
|
|
TokenStream(inner)
|
2017-01-07 23:04:49 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn token_stream_parse_items(stream: TokenStream) -> Result<Vec<P<ast::Item>>, LexError> {
|
2017-03-28 00:32:43 -05:00
|
|
|
with_sess(move |(sess, _)| {
|
2017-03-17 18:23:12 -05:00
|
|
|
let mut parser = parse::stream_to_parser(sess, stream.0);
|
2017-01-07 23:04:49 -06:00
|
|
|
let mut items = Vec::new();
|
|
|
|
|
|
|
|
while let Some(item) = try!(parser.parse_item().map_err(super::parse_to_lex_err)) {
|
|
|
|
items.push(item)
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(items)
|
|
|
|
})
|
2016-10-03 11:49:39 -05:00
|
|
|
}
|
2016-08-04 14:20:01 -05:00
|
|
|
|
2017-03-17 18:23:12 -05:00
|
|
|
pub fn token_stream_inner(stream: TokenStream) -> tokenstream::TokenStream {
|
|
|
|
stream.0
|
2016-10-03 11:49:39 -05:00
|
|
|
}
|
2016-08-04 14:20:01 -05:00
|
|
|
|
2016-10-03 11:49:39 -05:00
|
|
|
pub trait Registry {
|
|
|
|
fn register_custom_derive(&mut self,
|
|
|
|
trait_name: &str,
|
2016-11-08 05:15:02 -06:00
|
|
|
expand: fn(TokenStream) -> TokenStream,
|
|
|
|
attributes: &[&'static str]);
|
2017-01-07 23:04:49 -06:00
|
|
|
|
|
|
|
fn register_attr_proc_macro(&mut self,
|
|
|
|
name: &str,
|
|
|
|
expand: fn(TokenStream, TokenStream) -> TokenStream);
|
2017-02-27 14:03:19 -06:00
|
|
|
|
|
|
|
fn register_bang_proc_macro(&mut self,
|
|
|
|
name: &str,
|
|
|
|
expand: fn(TokenStream) -> TokenStream);
|
2016-10-03 11:49:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Emulate scoped_thread_local!() here essentially
|
|
|
|
thread_local! {
|
2017-03-28 00:32:43 -05:00
|
|
|
static CURRENT_SESS: Cell<(*const ParseSess, Mark)> =
|
|
|
|
Cell::new((0 as *const _, Mark::root()));
|
2016-10-03 11:49:39 -05:00
|
|
|
}
|
|
|
|
|
2017-03-28 00:32:43 -05:00
|
|
|
pub fn set_sess<F, R>(cx: &ExtCtxt, f: F) -> R
|
2016-10-03 11:49:39 -05:00
|
|
|
where F: FnOnce() -> R
|
|
|
|
{
|
2017-03-28 00:32:43 -05:00
|
|
|
struct Reset { prev: (*const ParseSess, Mark) }
|
2016-10-03 11:49:39 -05:00
|
|
|
|
|
|
|
impl Drop for Reset {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
CURRENT_SESS.with(|p| p.set(self.prev));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CURRENT_SESS.with(|p| {
|
|
|
|
let _reset = Reset { prev: p.get() };
|
2017-03-28 00:32:43 -05:00
|
|
|
p.set((cx.parse_sess, cx.current_expansion.mark));
|
2016-10-03 11:49:39 -05:00
|
|
|
f()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-03-28 00:32:43 -05:00
|
|
|
pub fn with_sess<F, R>(f: F) -> R
|
|
|
|
where F: FnOnce((&ParseSess, Mark)) -> R
|
2016-10-03 11:49:39 -05:00
|
|
|
{
|
|
|
|
let p = CURRENT_SESS.with(|p| p.get());
|
2017-03-28 00:32:43 -05:00
|
|
|
assert!(!p.0.is_null(), "proc_macro::__internal::with_sess() called \
|
|
|
|
before set_parse_sess()!");
|
|
|
|
f(unsafe { (&*p.0, p.1) })
|
2016-10-03 11:49:39 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-07 23:04:49 -06:00
|
|
|
fn parse_to_lex_err(mut err: DiagnosticBuilder) -> LexError {
|
|
|
|
err.cancel();
|
|
|
|
LexError { _inner: () }
|
|
|
|
}
|
|
|
|
|
2017-01-01 18:14:35 -06:00
|
|
|
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
2016-10-03 11:49:39 -05:00
|
|
|
impl FromStr for TokenStream {
|
|
|
|
type Err = LexError;
|
|
|
|
|
|
|
|
fn from_str(src: &str) -> Result<TokenStream, LexError> {
|
2017-03-28 00:32:43 -05:00
|
|
|
__internal::with_sess(|(sess, mark)| {
|
2016-10-03 11:49:39 -05:00
|
|
|
let src = src.to_string();
|
|
|
|
let name = "<proc-macro source code>".to_string();
|
2017-03-28 00:32:43 -05:00
|
|
|
let call_site = mark.expn_info().unwrap().call_site;
|
|
|
|
let stream = parse::parse_stream_from_source_str(name, src, sess, Some(call_site));
|
2017-02-20 23:05:59 -06:00
|
|
|
Ok(__internal::token_stream_wrap(stream))
|
2016-10-03 11:49:39 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2016-08-04 14:20:01 -05:00
|
|
|
|
2017-01-01 18:14:35 -06:00
|
|
|
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
2016-10-03 11:49:39 -05:00
|
|
|
impl fmt::Display for TokenStream {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2017-03-17 18:23:12 -05:00
|
|
|
self.0.fmt(f)
|
2016-10-03 11:49:39 -05:00
|
|
|
}
|
2016-08-04 14:20:01 -05:00
|
|
|
}
|