potent-quotables 0.1.0

A powerful macro for quoting Rust syntax
Documentation
#![doc = include_str!("../README.md")]

/// Quotes its argument tokens, yielding a [TokenStream].
///
/// ```
/// # use potent_quotables::pq;
/// let tokens = pq! { x * (y + 1) };
/// assert_eq!(tokens.to_string(), "x * (y + 1)");
/// ```
///
/// # Directives
///
/// Sequences of tokens starting with `#` are known as *directives* and activate special behaviors
/// as described in the following sections.
///
/// As an exception, the sequences `#[` and `#!` are *not* interpreted as directives and are instead
/// quoted just like any other tokens, allowing you to quote Rust attributes.
///
/// ```
/// # use potent_quotables::pq;
/// let tokens = pq! { #![foo] #[bar] };
/// assert_eq!(tokens.to_string(), "#! [foo] # [bar]");
/// ```
///
/// ## Interpolation
///
/// - **`#`<var>ident</var>**
/// - **`#(`<var>expr</var>`)`**
///
/// This directive evaluates <var>ident</var> or <var>expr</var>. The resulting value must implement
/// the [ToTokens] trait, which is used to convert the value into a sequence of tokens that will be
/// included in the [TokenStream].
///
/// ```
/// # use potent_quotables::pq;
/// let greeting = "hello";
/// let tokens = pq! { #greeting #(greeting.len()) };
/// assert_eq!(tokens.to_string(), "\"hello\" 5usize");
/// ```
///
/// Expressions more complex than a single identifier *must* be enclosed in parentheses.
///
/// ## Statement directives
///
/// - **`#do` <var>stmt</var>**
/// - **`#` <var>stmt</var>**, where `stmt` starts with one of the following keywords:
///
///   `break` `continue` `enum` `extern` `fn` `impl` `let` `mod` `pub` `return` `static` `struct`
///   `trait` `type` `use`
///
/// The main use cases for statement directives are declaring local variables with `let` and
/// evaluating expressions whose results should not (or cannot) be [interpolated](#interpolation).
///
/// ```
/// # use potent_quotables::pq;
/// let tokens = pq! {
///     #let mut x = 3;
///     #x
///     #do x += 2; // compound-assignment expression has type `()`, which cannot be interpolated
///     #x
/// };
/// assert_eq!(tokens.to_string(), "3i32 5i32");
/// ```
///
/// Another important use case allows using `break` or `continue` to manipulate control flow in a
/// loop—either a loop surrounding the `pq!` invocation or a loop introduced by a [control-flow
/// directive](#control-flow-directives).
///
/// ```
/// # use potent_quotables::pq;
/// loop {
///     pq! { #break; };
///     unreachable!()
/// }
/// ```
///
/// Statements usually end in a semicolon, but for some kinds of statements, the trailing semicolon
/// is optional. When an optional trailing semicolon is present in such a statement, it is always
/// treated as part of the directive, rather than as an unrelated token to be quoted. If you need to
/// quote a semicolon immediately after a statement directive whose semicolon is optional, you will
/// need to include the optional semicolon *and* the semicolon to be quoted.
///
/// ```
/// # use potent_quotables::pq;
/// let tokens = pq! {
///     #do {}; // optional trailing semicolon
///     ; // semicolon to be quoted
/// };
/// assert_eq!(tokens.to_string(), ";");
/// ```
///
/// ## Control-flow directives
///
/// These directives behave analogously to their corresponding Rust control-flow expressions, except
/// that their body blocks are treated as sequences of tokens to be quoted instead of code to be
/// executed.
///
/// Labeled loops are not supported.
///
/// - **`#if` <var>cond</var> `{` <var>token</var><sup>\*</sup> `}` (`else if` <var>cond</var> `{`
///   <var>token</var><sup>\*</sup> `}`)<sup>*</sup> (`else` `{` <var>token</var><sup>\*</sup>
///   `}`)<sup>?</sup>**
///
///   ```
///   # use potent_quotables::pq;
///   let greeting = "hello";
///   let tokens = pq! {
///       #if greeting.len() > 3 {
///           goodbye
///       } else if greeting.len() > 1 {
///           bye
///       } else {
///           nope
///       }
///   };
///   assert_eq!(tokens.to_string(), "goodbye");
///   ```
///
///   Note that an `else` keyword immediately following the "then" block is always treated as part
///   of the directive, rather than as an unrelated token to be quoted. If you need to quote the
///   `else` keyword immediately after a `#if` directive, you can use a no-op [statement
///   directive](#statement-directives) to separate them.
///
///   ```
///   # use potent_quotables::pq;
///   let tokens = pq! {
///       #if true { foo }
///       #do {} // no-op statement to separate the `else` from the `#if`
///       else
///   };
///   assert_eq!(tokens.to_string(), "foo else");
///   ```
///
/// - **`#while` <var>cond</var> `{` <var>token</var><sup>\*</sup> `}`**
///
///   ```
///   # use potent_quotables::pq;
///   let mut iter = ["fee", "fi", "fo", "fum"].into_iter();
///   let tokens = pq! {
///       #while let Some(word) = iter.next() {
///           #word;
///       }
///   };
///   assert_eq!(tokens.to_string(), "\"fee\" ; \"fi\" ; \"fo\" ; \"fum\" ;");
///   ```
///
/// - **`#for` <var>pat</var> `in` <var>expr</var> `{` <var>token</var><sup>\*</sup> `}`**
///
///   ```
///   # use potent_quotables::pq;
///   let tokens = pq! {
///       #for i in 0..5 {
///           #i
///       }
///   };
///   assert_eq!(tokens.to_string(), "0i32 1i32 2i32 3i32 4i32");
///   ```
///
/// - **`#loop` `{` <var>token</var><sup>\*</sup> `}`**
///
///   ```
///   # use potent_quotables::pq;
///   let tokens = pq! {
///       #loop {
///           *
///           #break;
///       }
///   };
///   assert_eq!(tokens.to_string(), "*");
///   ```
///
/// - **`#match` <var>expr</var> `{` ( <var>pat</var> `=>` `{` <var>token</var><sup>\*</sup> `}`
///   `,`<sup>?</sup> )<sup>*</sup> `}`**
///
///   The right-hand side of each arm must be a braced group, which is treated as a sequence of
///   tokens to be quoted.
///
///   ```
///   # use potent_quotables::pq;
///   let result = Some(1);
///   let tokens = pq! {
///       #match result {
///           Some(x) => { #x }
///           None => { nope }
///       }
///   };
///   assert_eq!(tokens.to_string(), "1i32");
///   ```
///
/// ## Formatted doc comments
///
/// - **`#//!` <var>text</var>**
/// - **`#///` <var>text</var>**
///
/// This directive produces a doc comment, with <var>text</var> treated as a format string à la
/// [std::fmt].
///
/// ```
/// # use potent_quotables::pq;
/// let greeting = "hello";
/// let recipient = Some(1);
/// let tokens = pq! {
///     #//! {greeting} world
///     #/// is {recipient:?} out there?
/// };
/// assert_eq!(
///     tokens.to_string(),
///     "#![doc = \" hello world\"] #[doc = \" is Some(1) out there?\"]",
/// );
/// ```
///
/// All named parameters in <var>text</var> must refer to variables in scope. Positional parameters
/// are not allowed because the directive's syntax does not provide a way to pass additional
/// arguments to the formatter.
///
/// # Scoping
///
/// The body of a `pq!` invocation introduces its own lexical scope. Additionally, each delimited
/// group introduces its own lexical scope.
///
/// ```
/// # use potent_quotables::pq;
/// let x = "outermost";
/// let tokens = pq! {
///     #let x = "outside";
///     {
///         #let x = "braced";
///         [
///             #let x = "bracketed";
///             (
///                 #let x = "parenthesized";
///                 #x
///             )
///             #x
///         ]
///         #x
///     }
///     #x
/// };
/// assert_eq!(x, "outermost");
/// assert_eq!(
///     tokens.to_string(),
///     "{ [(\"parenthesized\") \"bracketed\"] \"braced\" } \"outside\"",
/// );
/// ```
#[macro_export]
macro_rules! pq {
    ($($tts:tt)*) => {
        $crate::private::pq!($($tts)*)
    };
}

#[doc(no_inline)]
pub use proc_macro2::TokenStream;
#[doc(no_inline)]
pub use quote::ToTokens;

#[doc(hidden)]
pub mod private {
    pub use std::format;

    pub use potent_quotables_core::*;
    pub use potent_quotables_proc_macro::pq;
}