|
| 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 | +//! # Proc_Macro |
| 12 | +//! |
| 13 | +//! A library for procedural macro writers. |
| 14 | +//! |
| 15 | +//! ## Usage |
| 16 | +//! This package provides the `qquote!` macro for syntax creation, and the prelude |
| 17 | +//! (at libproc_macro::prelude) provides a number of operations: |
| 18 | +//! - `concat`, for concatenating two TokenStreams. |
| 19 | +//! - `ident_eq`, for checking if two identifiers are equal regardless of syntax context. |
| 20 | +//! - `str_to_token_ident`, for converting an `&str` into a Token. |
| 21 | +//! - `keyword_to_token_delim`, for converting a `parse::token::keywords::Keyword` into a |
| 22 | +//! Token. |
| 23 | +//! - `build_delimited`, for creating a new TokenStream from an existing one and a delimiter |
| 24 | +//! by wrapping the TokenStream in the delimiter. |
| 25 | +//! - `build_bracket_delimited`, `build_brace_delimited`, and `build_paren_delimited`, for |
| 26 | +//! easing the above. |
| 27 | +//! - `build_empty_args`, which returns a TokenStream containing `()`. |
| 28 | +//! - `lex`, which takes an `&str` and returns the TokenStream it represents. |
| 29 | +//! |
| 30 | +//! The `qquote!` macro also imports `syntax::ext::proc_macro_shim::prelude::*`, so you |
| 31 | +//! will need to `extern crate syntax` for usage. (This is a temporary solution until more |
| 32 | +//! of the external API in libproc_macro is stabilized to support the token construction |
| 33 | +//! operations that the qausiquoter relies on.) The shim file also provides additional |
| 34 | +//! operations, such as `build_block_emitter` (as used in the `cond` example below). |
| 35 | +//! |
| 36 | +//! ## TokenStreams |
| 37 | +//! |
| 38 | +//! TokenStreams serve as the basis of the macro system. They are, in essence, vectors of |
| 39 | +//! TokenTrees, where indexing treats delimited values as a single term. That is, the term |
| 40 | +//! `even(a+c) && even(b)` will be indexibly encoded as `even | (a+c) | even | (b)` where, |
| 41 | +//! in reality, `(a+c)` is actually a decorated pointer to `a | + | c`. |
| 42 | +//! |
| 43 | +//! If a user has a TokenStream that is a single, delimited value, they can use |
| 44 | +//! `maybe_delimited` to destruct it and receive the internal vector as a new TokenStream |
| 45 | +//! as: |
| 46 | +//! ``` |
| 47 | +//! `(a+c)`.maybe_delimited() ~> Some(a | + | c)` |
| 48 | +//! ``` |
| 49 | +//! |
| 50 | +//! Check the TokenStream documentation for more information; the structure also provides |
| 51 | +//! cheap concatenation and slicing. |
| 52 | +//! |
| 53 | +//! ## Quasiquotation |
| 54 | +//! |
| 55 | +//! The quasiquoter creates output that, when run, constructs the tokenstream specified as |
| 56 | +//! input. For example, `qquote!(5 + 5)` will produce a program, that, when run, will |
| 57 | +//! construct the TokenStream `5 | + | 5`. |
| 58 | +//! |
| 59 | +//! ### Unquoting |
| 60 | +//! |
| 61 | +//! Unquoting is currently done as `unquote`, and works by taking the single next |
| 62 | +//! TokenTree in the TokenStream as the unquoted term. Ergonomically, `unquote(foo)` works |
| 63 | +//! fine, but `unquote foo` is also supported. |
| 64 | +//! |
| 65 | +//! A simple example might be: |
| 66 | +//! |
| 67 | +//!``` |
| 68 | +//!fn double(tmp: TokenStream) -> TokenStream { |
| 69 | +//! qquote!(unquote(tmp) * 2) |
| 70 | +//!} |
| 71 | +//!``` |
| 72 | +//! |
| 73 | +//! ### Large Example: Implementing Scheme's `cond` |
| 74 | +//! |
| 75 | +//! Below is the full implementation of Scheme's `cond` operator. |
| 76 | +//! |
| 77 | +//! ``` |
| 78 | +//! fn cond_rec(input: TokenStream) -> TokenStream { |
| 79 | +//! if input.is_empty() { return quote!(); } |
| 80 | +//! |
| 81 | +//! let next = input.slice(0..1); |
| 82 | +//! let rest = input.slice_from(1..); |
| 83 | +//! |
| 84 | +//! let clause : TokenStream = match next.maybe_delimited() { |
| 85 | +//! Some(ts) => ts, |
| 86 | +//! _ => panic!("Invalid input"), |
| 87 | +//! }; |
| 88 | +//! |
| 89 | +//! // clause is ([test]) [rhs] |
| 90 | +//! if clause.len() < 2 { panic!("Invalid macro usage in cond: {:?}", clause) } |
| 91 | +//! |
| 92 | +//! let test: TokenStream = clause.slice(0..1); |
| 93 | +//! let rhs: TokenStream = clause.slice_from(1..); |
| 94 | +//! |
| 95 | +//! if ident_eq(&test[0], str_to_ident("else")) || rest.is_empty() { |
| 96 | +//! quote!({unquote(rhs)}) |
| 97 | +//! } else { |
| 98 | +//! quote!({if unquote(test) { unquote(rhs) } else { cond!(unquote(rest)) } }) |
| 99 | +//! } |
| 100 | +//! } |
| 101 | +//! ``` |
| 102 | +//! |
| 103 | +
|
| 104 | +#![crate_name = "proc_macro"] |
| 105 | +#![unstable(feature = "rustc_private", issue = "27812")] |
| 106 | +#![feature(plugin_registrar)] |
| 107 | +#![crate_type = "dylib"] |
| 108 | +#![crate_type = "rlib"] |
| 109 | +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", |
| 110 | + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", |
| 111 | + html_root_url = "https://doc.rust-lang.org/nightly/")] |
| 112 | +#![cfg_attr(not(stage0), deny(warnings))] |
| 113 | + |
| 114 | +#![feature(staged_api)] |
| 115 | +#![feature(rustc_diagnostic_macros)] |
| 116 | +#![feature(rustc_private)] |
| 117 | + |
| 118 | +extern crate rustc_plugin; |
| 119 | +extern crate syntax; |
| 120 | +extern crate syntax_pos; |
| 121 | +#[macro_use] extern crate log; |
| 122 | + |
| 123 | +mod qquote; |
| 124 | +pub mod build; |
| 125 | +pub mod parse; |
| 126 | +pub mod prelude; |
| 127 | +use qquote::qquote; |
| 128 | + |
| 129 | +use rustc_plugin::Registry; |
| 130 | + |
| 131 | +// ____________________________________________________________________________________________ |
| 132 | +// Main macro definition |
| 133 | + |
| 134 | +#[plugin_registrar] |
| 135 | +pub fn plugin_registrar(reg: &mut Registry) { |
| 136 | + reg.register_macro("qquote", qquote); |
| 137 | +} |
0 commit comments