potent_quotables/lib.rs
1#![doc = include_str!("../README.md")]
2
3/// Quotes its argument tokens, yielding a [TokenStream].
4///
5/// ```
6/// # use potent_quotables::pq;
7/// let tokens = pq! { x * (y + 1) };
8/// assert_eq!(tokens.to_string(), "x * (y + 1)");
9/// ```
10///
11/// # Directives
12///
13/// Sequences of tokens starting with `#` are known as *directives* and activate special behaviors
14/// as described in the following sections.
15///
16/// As an exception, the sequences `#[` and `#!` are *not* interpreted as directives and are instead
17/// quoted just like any other tokens, allowing you to quote Rust attributes.
18///
19/// ```
20/// # use potent_quotables::pq;
21/// let tokens = pq! { #![foo] #[bar] };
22/// assert_eq!(tokens.to_string(), "#! [foo] # [bar]");
23/// ```
24///
25/// ## Interpolation
26///
27/// - **`#`<var>ident</var>**
28/// - **`#(`<var>expr</var>`)`**
29///
30/// This directive evaluates <var>ident</var> or <var>expr</var>. The resulting value must implement
31/// the [ToTokens] trait, which is used to convert the value into a sequence of tokens that will be
32/// included in the [TokenStream].
33///
34/// ```
35/// # use potent_quotables::pq;
36/// let greeting = "hello";
37/// let tokens = pq! { #greeting #(greeting.len()) };
38/// assert_eq!(tokens.to_string(), "\"hello\" 5usize");
39/// ```
40///
41/// Expressions more complex than a single identifier *must* be enclosed in parentheses.
42///
43/// ## Statement directives
44///
45/// - **`#do` <var>stmt</var>**
46/// - **`#` <var>stmt</var>**, where `stmt` starts with one of the following keywords:
47///
48/// `break` `continue` `enum` `extern` `fn` `impl` `let` `mod` `pub` `return` `static` `struct`
49/// `trait` `type` `use`
50///
51/// The main use cases for statement directives are declaring local variables with `let` and
52/// evaluating expressions whose results should not (or cannot) be [interpolated](#interpolation).
53///
54/// ```
55/// # use potent_quotables::pq;
56/// let tokens = pq! {
57/// #let mut x = 3;
58/// #x
59/// #do x += 2; // compound-assignment expression has type `()`, which cannot be interpolated
60/// #x
61/// };
62/// assert_eq!(tokens.to_string(), "3i32 5i32");
63/// ```
64///
65/// Another important use case allows using `break` or `continue` to manipulate control flow in a
66/// loop—either a loop surrounding the `pq!` invocation or a loop introduced by a [control-flow
67/// directive](#control-flow-directives).
68///
69/// ```
70/// # use potent_quotables::pq;
71/// loop {
72/// pq! { #break; };
73/// unreachable!()
74/// }
75/// ```
76///
77/// Statements usually end in a semicolon, but for some kinds of statements, the trailing semicolon
78/// is optional. When an optional trailing semicolon is present in such a statement, it is always
79/// treated as part of the directive, rather than as an unrelated token to be quoted. If you need to
80/// quote a semicolon immediately after a statement directive whose semicolon is optional, you will
81/// need to include the optional semicolon *and* the semicolon to be quoted.
82///
83/// ```
84/// # use potent_quotables::pq;
85/// let tokens = pq! {
86/// #do {}; // optional trailing semicolon
87/// ; // semicolon to be quoted
88/// };
89/// assert_eq!(tokens.to_string(), ";");
90/// ```
91///
92/// ## Control-flow directives
93///
94/// These directives behave analogously to their corresponding Rust control-flow expressions, except
95/// that their body blocks are treated as sequences of tokens to be quoted instead of code to be
96/// executed.
97///
98/// Labeled loops are not supported.
99///
100/// - **`#if` <var>cond</var> `{` <var>token</var><sup>\*</sup> `}` (`else if` <var>cond</var> `{`
101/// <var>token</var><sup>\*</sup> `}`)<sup>*</sup> (`else` `{` <var>token</var><sup>\*</sup>
102/// `}`)<sup>?</sup>**
103///
104/// ```
105/// # use potent_quotables::pq;
106/// let greeting = "hello";
107/// let tokens = pq! {
108/// #if greeting.len() > 3 {
109/// goodbye
110/// } else if greeting.len() > 1 {
111/// bye
112/// } else {
113/// nope
114/// }
115/// };
116/// assert_eq!(tokens.to_string(), "goodbye");
117/// ```
118///
119/// Note that an `else` keyword immediately following the "then" block is always treated as part
120/// of the directive, rather than as an unrelated token to be quoted. If you need to quote the
121/// `else` keyword immediately after a `#if` directive, you can use a no-op [statement
122/// directive](#statement-directives) to separate them.
123///
124/// ```
125/// # use potent_quotables::pq;
126/// let tokens = pq! {
127/// #if true { foo }
128/// #do {} // no-op statement to separate the `else` from the `#if`
129/// else
130/// };
131/// assert_eq!(tokens.to_string(), "foo else");
132/// ```
133///
134/// - **`#while` <var>cond</var> `{` <var>token</var><sup>\*</sup> `}`**
135///
136/// ```
137/// # use potent_quotables::pq;
138/// let mut iter = ["fee", "fi", "fo", "fum"].into_iter();
139/// let tokens = pq! {
140/// #while let Some(word) = iter.next() {
141/// #word;
142/// }
143/// };
144/// assert_eq!(tokens.to_string(), "\"fee\" ; \"fi\" ; \"fo\" ; \"fum\" ;");
145/// ```
146///
147/// - **`#for` <var>pat</var> `in` <var>expr</var> `{` <var>token</var><sup>\*</sup> `}`**
148///
149/// ```
150/// # use potent_quotables::pq;
151/// let tokens = pq! {
152/// #for i in 0..5 {
153/// #i
154/// }
155/// };
156/// assert_eq!(tokens.to_string(), "0i32 1i32 2i32 3i32 4i32");
157/// ```
158///
159/// - **`#loop` `{` <var>token</var><sup>\*</sup> `}`**
160///
161/// ```
162/// # use potent_quotables::pq;
163/// let tokens = pq! {
164/// #loop {
165/// *
166/// #break;
167/// }
168/// };
169/// assert_eq!(tokens.to_string(), "*");
170/// ```
171///
172/// - **`#match` <var>expr</var> `{` ( <var>pat</var> `=>` `{` <var>token</var><sup>\*</sup> `}`
173/// `,`<sup>?</sup> )<sup>*</sup> `}`**
174///
175/// The right-hand side of each arm must be a braced group, which is treated as a sequence of
176/// tokens to be quoted.
177///
178/// ```
179/// # use potent_quotables::pq;
180/// let result = Some(1);
181/// let tokens = pq! {
182/// #match result {
183/// Some(x) => { #x }
184/// None => { nope }
185/// }
186/// };
187/// assert_eq!(tokens.to_string(), "1i32");
188/// ```
189///
190/// ## Formatted doc comments
191///
192/// - **`#//!` <var>text</var>**
193/// - **`#///` <var>text</var>**
194///
195/// This directive produces a doc comment, with <var>text</var> treated as a format string à la
196/// [std::fmt].
197///
198/// ```
199/// # use potent_quotables::pq;
200/// let greeting = "hello";
201/// let recipient = Some(1);
202/// let tokens = pq! {
203/// #//! {greeting} world
204/// #/// is {recipient:?} out there?
205/// };
206/// assert_eq!(
207/// tokens.to_string(),
208/// "#![doc = \" hello world\"] #[doc = \" is Some(1) out there?\"]",
209/// );
210/// ```
211///
212/// All named parameters in <var>text</var> must refer to variables in scope. Positional parameters
213/// are not allowed because the directive's syntax does not provide a way to pass additional
214/// arguments to the formatter.
215///
216/// # Scoping
217///
218/// The body of a `pq!` invocation introduces its own lexical scope. Additionally, each delimited
219/// group introduces its own lexical scope.
220///
221/// ```
222/// # use potent_quotables::pq;
223/// let x = "outermost";
224/// let tokens = pq! {
225/// #let x = "outside";
226/// {
227/// #let x = "braced";
228/// [
229/// #let x = "bracketed";
230/// (
231/// #let x = "parenthesized";
232/// #x
233/// )
234/// #x
235/// ]
236/// #x
237/// }
238/// #x
239/// };
240/// assert_eq!(x, "outermost");
241/// assert_eq!(
242/// tokens.to_string(),
243/// "{ [(\"parenthesized\") \"bracketed\"] \"braced\" } \"outside\"",
244/// );
245/// ```
246#[macro_export]
247macro_rules! pq {
248 ($($tts:tt)*) => {
249 $crate::private::pq!($($tts)*)
250 };
251}
252
253#[doc(no_inline)]
254pub use proc_macro2::TokenStream;
255#[doc(no_inline)]
256pub use quote::ToTokens;
257
258#[doc(hidden)]
259pub mod private {
260 pub use std::format;
261
262 pub use potent_quotables_core::*;
263 pub use potent_quotables_proc_macro::pq;
264}