summary refs log tree commit diff
path: root/src/libproc_macro/lib.rs
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2016-10-03 09:49:39 -0700
committerAlex Crichton <alex@alexcrichton.com>2016-10-06 11:07:23 -0700
commit2148bdfcc7ea7b9614d8cbe596cbe7bb75b57cd1 (patch)
tree4a88c4f26d3a898cb9ac26aa6a06fd074253d5a3 /src/libproc_macro/lib.rs
parent7a26aeca77bcf334747eddb630e3b9475149b7f5 (diff)
downloadrust-2148bdfcc7ea7b9614d8cbe596cbe7bb75b57cd1.tar.gz
rust-2148bdfcc7ea7b9614d8cbe596cbe7bb75b57cd1.zip
rustc: Rename rustc_macro to proc_macro
This commit blanket renames the `rustc_macro` infrastructure to `proc_macro`,
which reflects the general consensus of #35900. A follow up PR to Cargo will be
required to purge the `rustc-macro` name as well.
Diffstat (limited to 'src/libproc_macro/lib.rs')
-rw-r--r--src/libproc_macro/lib.rs250
1 files changed, 140 insertions, 110 deletions
diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs
index 9e25cb88e01..4b9b92fb3bb 100644
--- a/src/libproc_macro/lib.rs
+++ b/src/libproc_macro/lib.rs
@@ -8,130 +8,160 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! # Proc_Macro
+//! A support library for macro authors when defining new macros.
 //!
-//! A library for procedural macro writers.
+//! 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]`.
 //!
-//! ## Usage
-//! This package provides the `qquote!` macro for syntax creation, and the prelude
-//! (at libproc_macro::prelude) provides a number of operations:
-//! - `concat`, for concatenating two TokenStreams.
-//! - `ident_eq`, for checking if two identifiers are equal regardless of syntax context.
-//! - `str_to_token_ident`, for converting an `&str` into a Token.
-//! - `keyword_to_token_delim`, for converting a `parse::token::keywords::Keyword` into a
-//!    Token.
-//! - `build_delimited`, for creating a new TokenStream from an existing one and a delimiter
-//!    by wrapping the TokenStream in the delimiter.
-//! - `build_bracket_delimited`, `build_brace_delimited`, and `build_paren_delimited`, for
-//!    easing the above.
-//! - `build_empty_args`, which returns a TokenStream containing `()`.
-//! - `lex`, which takes an `&str` and returns the TokenStream it represents.
+//! Added recently as part of [RFC 1681] this crate is currently *unstable* and
+//! requires the `#![feature(proc_macro_lib)]` directive to use.
 //!
-//! The `qquote!` macro also imports `syntax::ext::proc_macro_shim::prelude::*`, so you
-//! will need to `extern crate syntax` for usage. (This is a temporary solution until more
-//! of the external API in libproc_macro is stabilized to support the token construction
-//! operations that the qausiquoter relies on.) The shim file also provides additional
-//! operations, such as `build_block_emitter` (as used in the `cond` example below).
-//!
-//! ## TokenStreams
-//!
-//! TokenStreams serve as the basis of the macro system. They are, in essence, vectors of
-//! TokenTrees, where indexing treats delimited values as a single term. That is, the term
-//! `even(a+c) && even(b)` will be indexibly encoded as `even | (a+c) | even | (b)` where,
-//! in reality, `(a+c)` is actually a decorated pointer to `a | + | c`.
-//!
-//! If a user has a TokenStream that is a single, delimited value, they can use
-//! `maybe_delimited` to destruct it and receive the internal vector as a new TokenStream
-//! as:
-//! ```
-//! `(a+c)`.maybe_delimited() ~> Some(a | + | c)`
-//! ```
-//!
-//! Check the TokenStream documentation for more information; the structure also provides
-//! cheap concatenation and slicing.
-//!
-//! ## Quasiquotation
-//!
-//! The quasiquoter creates output that, when run, constructs the tokenstream specified as
-//! input. For example, `qquote!(5 + 5)` will produce a program, that, when run, will
-//! construct the TokenStream `5 | + | 5`.
-//!
-//! ### Unquoting
-//!
-//! Unquoting is currently done as `unquote`, and works by taking the single next
-//! TokenTree in the TokenStream as the unquoted term. Ergonomically, `unquote(foo)` works
-//! fine, but `unquote foo` is also supported.
-//!
-//! A simple example might be:
-//!
-//!```
-//!fn double(tmp: TokenStream) -> TokenStream {
-//!    qquote!(unquote(tmp) * 2)
-//!}
-//!```
-//!
-//! ### Large Example: Implementing Scheme's `cond`
-//!
-//! Below is the full implementation of Scheme's `cond` operator.
-//!
-//! ```
-//! fn cond_rec(input: TokenStream) -> TokenStream {
-//!   if input.is_empty() { return quote!(); }
-//!
-//!   let next = input.slice(0..1);
-//!   let rest = input.slice_from(1..);
-//!
-//!   let clause : TokenStream = match next.maybe_delimited() {
-//!     Some(ts) => ts,
-//!     _ => panic!("Invalid input"),
-//!   };
-//!
-//!   // clause is ([test]) [rhs]
-//!   if clause.len() < 2 { panic!("Invalid macro usage in cond: {:?}", clause) }
-//!
-//!   let test: TokenStream = clause.slice(0..1);
-//!   let rhs: TokenStream = clause.slice_from(1..);
-//!
-//!   if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() {
-//!     quote!({unquote(rhs)})
-//!   } else {
-//!     quote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } })
-//!   }
-//! }
-//! ```
+//! [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
 //!
+//! 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.
 
 #![crate_name = "proc_macro"]
-#![unstable(feature = "rustc_private", issue = "27812")]
-#![feature(plugin_registrar)]
-#![crate_type = "dylib"]
+#![unstable(feature = "proc_macro_lib", issue = "27812")]
 #![crate_type = "rlib"]
-#![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/")]
+#![crate_type = "dylib"]
 #![cfg_attr(not(stage0), deny(warnings))]
+#![deny(missing_docs)]
 
-#![feature(staged_api)]
-#![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
+#![feature(staged_api)]
+#![feature(lang_items)]
 
-extern crate rustc_plugin;
 extern crate syntax;
-extern crate syntax_pos;
-#[macro_use] extern crate log;
 
-mod qquote;
-pub mod build;
-pub mod parse;
-pub mod prelude;
-use qquote::qquote;
+use std::fmt;
+use std::str::FromStr;
+
+use syntax::ast;
+use syntax::parse;
+use syntax::ptr::P;
+
+/// 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!
+pub struct TokenStream {
+    inner: Vec<P<ast::Item>>,
+}
+
+/// Error returned from `TokenStream::from_str`.
+#[derive(Debug)]
+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;
+
+    use syntax::ast;
+    use syntax::ptr::P;
+    use syntax::parse::ParseSess;
+    use super::TokenStream;
+
+    pub fn new_token_stream(item: P<ast::Item>) -> TokenStream {
+        TokenStream { inner: vec![item] }
+    }
 
-use rustc_plugin::Registry;
+    pub fn token_stream_items(stream: TokenStream) -> Vec<P<ast::Item>> {
+        stream.inner
+    }
 
-// ____________________________________________________________________________________________
-// Main macro definition
+    pub trait Registry {
+        fn register_custom_derive(&mut self,
+                                  trait_name: &str,
+                                  expand: fn(TokenStream) -> TokenStream);
+    }
+
+    // Emulate scoped_thread_local!() here essentially
+    thread_local! {
+        static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _);
+    }
+
+    pub fn set_parse_sess<F, R>(sess: &ParseSess, f: F) -> R
+        where F: FnOnce() -> R
+    {
+        struct Reset { prev: *const ParseSess }
+
+        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() };
+            p.set(sess);
+            f()
+        })
+    }
+
+    pub fn with_parse_sess<F, R>(f: F) -> R
+        where F: FnOnce(&ParseSess) -> R
+    {
+        let p = CURRENT_SESS.with(|p| p.get());
+        assert!(!p.is_null());
+        f(unsafe { &*p })
+    }
+}
+
+impl FromStr for TokenStream {
+    type Err = LexError;
+
+    fn from_str(src: &str) -> Result<TokenStream, LexError> {
+        __internal::with_parse_sess(|sess| {
+            let src = src.to_string();
+            let cfg = Vec::new();
+            let name = "<proc-macro source code>".to_string();
+            let mut parser = parse::new_parser_from_source_str(sess, cfg, name,
+                                                               src);
+            let mut ret = TokenStream { inner: Vec::new() };
+            loop {
+                match parser.parse_item() {
+                    Ok(Some(item)) => ret.inner.push(item),
+                    Ok(None) => return Ok(ret),
+                    Err(mut err) => {
+                        err.cancel();
+                        return Err(LexError { _inner: () })
+                    }
+                }
+            }
+        })
+    }
+}
 
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
-    reg.register_macro("qquote", qquote);
+impl fmt::Display for TokenStream {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        for item in self.inner.iter() {
+            let item = syntax::print::pprust::item_to_string(item);
+            try!(f.write_str(&item));
+            try!(f.write_str("\n"));
+        }
+        Ok(())
+    }
 }