genco/
lib.rs

1//! [<img alt="github" src="https://img.shields.io/badge/github-udoprog/genco-8da0cb?style=for-the-badge&logo=github" height="20">](https://github.com/udoprog/genco)
2//! [<img alt="crates.io" src="https://img.shields.io/crates/v/genco.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/genco)
3//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-genco-66c2a5?style=for-the-badge&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/genco)
4//!
5//! A whitespace-aware quasiquoter for beautiful code generation.
6//!
7//! Central to genco are the [`quote!`] and [`quote_in!`] procedural macros which
8//! ease the construction of [token streams].
9//!
10//! This project solves the following language-specific concerns:
11//!
12//! * **Imports** — Generates and groups [import statements] as they are used.
13//!   So you only import what you use, with no redundancy. We also do our best
14//!   to [solve namespace conflicts].
15//!
16//! * **String Quoting** — genco knows how to [quote strings]. And can even
17//!   [interpolate] values *into* the quoted string if it's supported by the
18//!   language.
19//!
20//! * **Structural Indentation** — The quoter relies on intuitive
21//!   [whitespace detection] to structurally sort out spacings and indentation.
22//!   Allowing genco to generate beautiful readable code with minimal effort.
23//!   This is also a requirement for generating correctly behaving code in
24//!   languages like Python where [indentation is meaningful].
25//!
26//! * **Language Customization** — Building support for new languages is a
27//!   piece of cake with the help of the [impl_lang!] macro.
28//!
29//! <br>
30//!
31//! To support line changes during [whitespace detection], we depend on span
32//! information which was made available in Rust `1.88`. Before that, we rely on
33//! a nightly [`proc_macro_span` feature] to work.
34//!
35//! *Prior to this version of Rust* if you want fully functional whitespace
36//! detection you must build and run projects using genco with a `nightly`
37//! compiler. This is important for whitespace-sensitive languages like python.
38//!
39//! You can try the difference between:
40//!
41//! ```bash
42//! cargo run --example rust
43//! ```
44//!
45//! And:
46//!
47//! ```bash
48//! cargo +nightly run --example rust
49//! ```
50//!
51//! [`proc_macro_span` feature]: https://github.com/rust-lang/rust/issues/54725
52//!
53//! <br>
54//!
55//! ## Supported Languages
56//!
57//! The following are languages which have built-in support in genco.
58//!
59//! * [🦀 <b>Rust</b>][rust]<br>
60//!   <small>[Example][rust-example]</small>
61//!
62//! * [☕ <b>Java</b>][java]<br>
63//!   <small>[Example][java-example]</small>
64//!
65//! * [🎼 <b>C#</b>][c#]<br>
66//!   <small>[Example][c#-example]</small>
67//!
68//! * [🐿️ <b>Go</b>][go]<br>
69//!   <small>[Example][go-example]</small>
70//!
71//! * [🎯 <b>Dart</b>][dart]<br>
72//!   <small>[Example][dart-example]</small>
73//!
74//! * [🌐 <b>JavaScript</b>][js]<br>
75//!   <small>[Example][js-example]</small>
76//!
77//! * [🇨 <b>C</b>][c]<br>
78//!   <small>[Example][c-example]</small>
79//!
80//! * [🐍 <b>Python</b>][python]<br>
81//!   <small>[Example][python-example]</small>
82//!
83//! <small>Is your favorite language missing? <b>[Open an issue!]</b></small>
84//!
85//! You can run one of the examples by:
86//!
87//! ```bash
88//! cargo +nightly run --example rust
89//! ```
90//!
91//! <br>
92//!
93//! ## Rust Example
94//!
95//! The following is a simple program producing Rust code to stdout with custom
96//! configuration:
97//!
98//! ```rust,no_run
99//! use genco::prelude::*;
100//!
101//! let hash_map = rust::import("std::collections", "HashMap");
102//!
103//! let tokens: rust::Tokens = quote! {
104//!     fn main() {
105//!         let mut m = $hash_map::new();
106//!         m.insert(1u32, 2u32);
107//!     }
108//! };
109//!
110//! println!("{}", tokens.to_file_string()?);
111//! # Ok::<_, genco::fmt::Error>(())
112//! ```
113//!
114//! This would produce:
115//!
116//! ```rust,no_test
117//! use std::collections::HashMap;
118//!
119//! fn main() {
120//!     let mut m = HashMap::new();
121//!     m.insert(1u32, 2u32);
122//! }
123//! ```
124//!
125//! <br>
126//!
127//! [`quote_in!`]: <https://docs.rs/genco/latest/genco/macro.quote_in.html>
128//! [`quote!`]: <https://docs.rs/genco/latest/genco/macro.quote.html>
129//! [`quoted()`]: <https://docs.rs/genco/latest/genco/tokens/fn.quoted.html>
130//! [c-example]: <https://github.com/udoprog/genco/blob/master/examples/c.rs>
131//! [c]: <https://docs.rs/genco/latest/genco/lang/c/index.html>
132//! [c#-example]: <https://github.com/udoprog/genco/blob/master/examples/csharp.rs>
133//! [c#]: <https://docs.rs/genco/latest/genco/lang/csharp/index.html>
134//! [dart-example]: <https://github.com/udoprog/genco/blob/master/examples/dart.rs>
135//! [dart]: <https://docs.rs/genco/latest/genco/lang/dart/index.html>
136//! [go-example]: <https://github.com/udoprog/genco/blob/master/examples/go.rs>
137//! [go]: <https://docs.rs/genco/latest/genco/lang/go/index.html>
138//! [impl_lang!]: <https://docs.rs/genco/latest/genco/macro.impl_lang.html>
139//! [import statements]: <https://docs.rs/genco/latest/genco/macro.quote.html#imports>
140//! [indentation is meaningful]: <https://docs.python.org/3/faq/design.html#why-does-python-use-indentation-for-grouping-of-statements>
141//! [interpolate]: <https://docs.rs/genco/latest/genco/macro.quote.html#quoted-string-interpolation>
142//! [java-example]: <https://github.com/udoprog/genco/blob/master/examples/java.rs>
143//! [java]: <https://docs.rs/genco/latest/genco/lang/java/index.html>
144//! [js-example]: <https://github.com/udoprog/genco/blob/master/examples/js.rs>
145//! [js]: <https://docs.rs/genco/latest/genco/lang/js/index.html>
146//! [Open an issue!]: <https://github.com/udoprog/genco/issues/new>
147//! [python-example]: <https://github.com/udoprog/genco/blob/master/examples/python.rs>
148//! [python]: <https://docs.rs/genco/latest/genco/lang/python/index.html>
149//! [quote strings]: <https://docs.rs/genco/latest/genco/macro.quote.html#string-quoting>
150//! [rust-example]: <https://github.com/udoprog/genco/blob/master/examples/rust.rs>
151//! [rust]: <https://docs.rs/genco/latest/genco/lang/rust/index.html>
152//! [solve namespace conflicts]: <https://docs.rs/genco/latest/genco/lang/csharp/fn.import.html>
153//! [token streams]: <https://docs.rs/genco/latest/genco/tokens/struct.Tokens.html>
154//! [whitespace detection]: <https://docs.rs/genco/latest/genco/macro.quote.html#whitespace-detection>
155
156#![deny(missing_docs)]
157#![deny(rustdoc::broken_intra_doc_links)]
158#![allow(clippy::needless_doctest_main)]
159#![no_std]
160
161#[cfg(feature = "std")]
162extern crate std;
163
164#[cfg(feature = "alloc")]
165extern crate alloc;
166
167#[cfg(not(feature = "alloc"))]
168compile_error!("genco: The `alloc` feature must be enabled");
169
170/// Whitespace sensitive quasi-quoting.
171///
172/// This and the [`quote_in!`] macro is the thing that this library revolves
173/// around.
174///
175/// It provides a flexible and intuitive mechanism for efficiently generating
176/// beautiful code directly inside of Rust.
177///
178/// > Note that this macro **can only detect line changes** if it's built with
179/// > Rust 1.88 or by using a `nightly` compiler. See the [main genco
180/// > documentation] for more information.
181///
182/// ```
183/// use genco::prelude::*;
184///
185/// let hash_map = &dart::import("dart:collection", "HashMap");
186///
187/// let tokens: dart::Tokens = quote! {
188///     print_greeting(String name) {
189///         print($[str](Hello $(name)));
190///     }
191///
192///     $hash_map<int, String> map() {
193///         return new $hash_map<int, String>();
194///     }
195/// };
196///
197/// println!("{}", tokens.to_file_string()?);
198/// # Ok::<_, genco::fmt::Error>(())
199/// ```
200///
201/// # Interpolation
202///
203/// Variables are interpolated using `$`, so to include the variable `test`, you
204/// would write `$test`. Interpolated variables must implement [`FormatInto`].
205/// Expressions can be interpolated with `$(<expr>)`.
206///
207/// > *Note:* The `$` punctuation itself can be escaped by repeating it twice.
208/// > So `$$` would produce a single `$` token.
209///
210/// ```
211/// use genco::prelude::*;
212///
213/// let hash_map = rust::import("std::collections", "HashMap");
214///
215/// let tokens: rust::Tokens = quote! {
216///     struct Quoted {
217///         field: $hash_map<u32, u32>,
218///     }
219/// };
220///
221/// assert_eq!(
222///     vec![
223///         "use std::collections::HashMap;",
224///         "",
225///         "struct Quoted {",
226///         "    field: HashMap<u32, u32>,",
227///         "}",
228///     ],
229///     tokens.to_file_vec()?,
230/// );
231/// # Ok::<_, genco::fmt::Error>(())
232/// ```
233///
234/// <br>
235///
236/// The following is an expression interpolated with `$(<expr>)`.
237///
238/// ```
239/// use genco::prelude::*;
240///
241/// let tokens: genco::Tokens = quote! {
242///     hello $("world".to_uppercase())
243/// };
244///
245/// assert_eq!("hello WORLD", tokens.to_string()?);
246/// # Ok::<_, genco::fmt::Error>(())
247/// ```
248///
249/// <br>
250///
251/// Interpolations are evaluated in the same scope as the macro, so you can
252/// freely make use of Rust operations like the try keyword (`?`) if
253/// appropriate:
254///
255/// ```
256/// use std::error::Error;
257///
258/// use genco::prelude::*;
259///
260/// fn age_fn(age: &str) -> Result<rust::Tokens, Box<dyn Error>> {
261///     Ok(quote! {
262///         fn age() {
263///             println!("You are {} years old!", $(str::parse::<u32>(age)?));
264///         }
265///     })
266/// }
267/// ```
268///
269/// [`FormatInto`]: crate::tokens::FormatInto
270/// [main genco documentation]: https://docs.rs/genco
271///
272/// <br>
273///
274/// # Escape Sequences
275///
276/// Because this macro is *whitespace sensitive*, it might sometimes be
277/// necessary to provide hints of where whitespace should be inserted.
278///
279/// `quote!` trims any trailing and leading whitespace that it sees. So
280/// `quote!(Hello )` is the same as `quote!(Hello)`. To include a space at the
281/// end, we can use the special `$[' ']` escape sequence:
282/// `quote!(Hello$[' '])`.
283///
284/// The available escape sequences are:
285///
286/// * `$[' ']` — Inserts spacing between tokens. This corresponds to the
287///   [Tokens::space] function.
288///
289/// * `$['\r']` — Inserts a push operation. Push operations makes sure that
290///   any following tokens are on their own dedicated line. This corresponds to
291///   the [Tokens::push] function.
292///
293/// * `$['\n']` — Inserts a forced line. Line operations makes sure that any
294///   following tokens have an empty line separating them. This corresponds to
295///   the [Tokens::line] function.
296///
297/// ```
298/// use genco::prelude::*;
299///
300/// let numbers = 3..=5;
301///
302/// let tokens: Tokens<()> = quote!(foo$['\r']bar$['\n']baz$[' ']biz);
303///
304/// assert_eq!("foo\nbar\n\nbaz biz", tokens.to_string()?);
305/// # Ok::<_, genco::fmt::Error>(())
306/// ```
307///
308/// <br>
309///
310/// # String Quoting
311///
312/// Literal strings like `"hello"` are automatically quoted for the target
313/// language according to its [Lang::write_quoted] implementation.
314///
315/// [Lang::write_quoted]: crate::lang::Lang::write_quoted
316///
317/// ```
318/// use genco::prelude::*;
319///
320/// let tokens: java::Tokens = quote! {
321///     "hello world 😊"
322///     $(quoted("hello world 😊"))
323///     $("\"hello world 😊\"")
324///     $[str](hello world $[const]("😊"))
325/// };
326///
327/// assert_eq!(
328///     vec![
329///         "\"hello world \\ud83d\\ude0a\"",
330///         "\"hello world \\ud83d\\ude0a\"",
331///         "\"hello world 😊\"",
332///         "\"hello world \\ud83d\\ude0a\"",
333///     ],
334///     tokens.to_file_vec()?,
335/// );
336/// # Ok::<_, genco::fmt::Error>(())
337/// ```
338///
339/// # Efficient String Quoting
340///
341/// It's worth investigating the different forms of tokens produced by the
342/// above example.
343///
344/// * The first one is a static *quoted string*.
345/// * The second one is a boxed *quoted string*, who's content will be copied
346///   and is stored on the heap.
347/// * The third one is a static *literal* which bypasses language quoting
348///   entirely.
349/// * Finally the fourth one is an interpolated string. They are really neat,
350///   and will be covered more in the next section. It's worth noting that
351///   `$("😊")` is used, because 😊 is not a valid identifier in Rust. So this
352///   example showcases how strings can be directly embedded in an
353///   interpolation.
354///
355/// Here you can see the items produced by the macro.
356///
357/// ```
358/// # use genco::prelude::*;
359/// # let tokens: rust::Tokens = quote! {
360/// #     "hello world 😊"
361/// #     $(quoted("hello world 😊"))
362/// #     $("\"hello world 😊\"")
363/// #     $[str](hello world $[const]("😊"))
364/// # };
365/// use genco::tokens::{Item, ItemStr};
366///
367/// assert_eq!(
368///     vec![
369///         Item::open_quote(false),
370///         Item::literal(ItemStr::static_("hello world 😊")),
371///         Item::close_quote(),
372///         Item::push(),
373///         Item::open_quote(false),
374///         Item::literal("hello world 😊".into()),
375///         Item::close_quote(),
376///         Item::push(),
377///         Item::literal(ItemStr::static_("\"hello world 😊\"")),
378///         Item::push(),
379///         Item::open_quote(false),
380///         Item::literal(ItemStr::static_("hello world 😊")),
381///         Item::close_quote()
382///     ],
383///     tokens,
384/// );
385/// # Ok::<_, genco::fmt::Error>(())
386/// ```
387///
388/// <br>
389///
390/// # Quoted String Interpolation
391///
392/// Some languages support interpolating values into strings.
393///
394/// Examples of these are:
395///
396/// * JavaScript - With [template literals] `` `Hello ${a}` `` (note the
397///   backticks).
398/// * Dart - With [interpolated strings] like `"Hello $a"` or `"Hello ${a +
399///   b}"`.
400///
401/// The [`quote!`] macro supports this through `$[str](<content>)`. This will
402/// produce literal strings with the appropriate language-specific quoting and
403/// string interpolation formats used.
404///
405/// Components of the string are runtime evaluated with the typical variable
406/// escape sequences `$ident`, `$(<expr>)`. In order to interpolate the string
407/// at compile time we can instead make use of `$[const](<content>)` like you can see with the smile below:
408///
409/// ```
410/// use genco::prelude::*;
411///
412/// let smile = "😊";
413///
414/// let t: js::Tokens = quote!($[str](Hello $[const](smile) $world));
415/// assert_eq!("`Hello 😊 ${world}`", t.to_string()?);
416/// # Ok::<_, genco::fmt::Error>(())
417/// ```
418///
419/// Interpolated values are specified with `$(<quoted>)`. And `$` itself is
420/// escaped by repeating it twice through `$$`. The `<quoted>` section is
421/// interpreted the same as in the [`quote!`] macro, but is whitespace sensitive.
422/// This means that `$(foo)` is not the same as `$(foo )` since the latter will
423/// have a space preserved at the end.
424///
425/// ```
426/// use genco::prelude::*;
427///
428/// let smile = "😊";
429///
430/// let t: dart::Tokens = quote!($[str](Hello $[const](smile) $(world)));
431/// assert_eq!("\"Hello 😊 $world\"", t.to_string()?);
432///
433/// let t: dart::Tokens = quote!($[str](Hello $[const](smile) $(a + b)));
434/// assert_eq!("\"Hello 😊 ${a + b}\"", t.to_string()?);
435///
436/// let t: js::Tokens = quote!($[str](Hello $[const](smile) $(world)));
437/// assert_eq!("`Hello 😊 ${world}`", t.to_string()?);
438/// # Ok::<_, genco::fmt::Error>(())
439/// ```
440///
441/// <br>
442///
443/// [template literals]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
444/// [interpolated strings]: https://medium.com/run-dart/dart-dartlang-introduction-string-interpolation-8ed99174119a
445///
446/// # Control Flow
447///
448/// [`quote!`] provides some limited mechanisms for control flow inside of the
449/// macro for convenience. The supported mechanisms are:
450///
451/// * [Loops](#loops) - `$(for <bindings> in <expr> [join (<quoted>)] => <quoted>)`.
452/// * [Conditionals](#conditionals) - `$(if <pattern> => <quoted>)`.
453/// * [Match Statements](#match-statements) - `$(match <expr> { [<pattern> => <quoted>,]* })`.
454///
455/// <br>
456///
457/// # Loops
458///
459/// To repeat a pattern you can use `$(for <bindings> in <expr> { <quoted> })`,
460/// where `<expr>` is an iterator.
461///
462/// It is also possible to use the more compact `$(for <bindings> in <expr> =>
463/// <quoted>)` (note the arrow).
464///
465/// `<quoted>` will be treated as a quoted expression, so anything which works
466/// during regular quoting will work here as well, with the addition that
467/// anything defined in `<bindings>` will be made available to the statement.
468///
469/// ```
470/// use genco::prelude::*;
471///
472/// let numbers = 3..=5;
473///
474/// let tokens: Tokens<()> = quote! {
475///     Your numbers are: $(for n in numbers => $n$[' '])
476/// };
477///
478/// assert_eq!("Your numbers are: 3 4 5", tokens.to_string()?);
479/// # Ok::<_, genco::fmt::Error>(())
480/// ```
481///
482/// <br>
483///
484/// # Joining Loops
485///
486/// You can add `join (<quoted>)` to the end of a repetition.
487///
488/// The expression specified in `join (<quoted>)` is added _between_ each
489/// element produced by the loop.
490///
491/// > *Note:* The argument to `join` is *whitespace sensitive*, so leading and
492/// > trailing is preserved. `join (,)` and `join (, )` would therefore produce
493/// > different results.
494///
495/// ```
496/// use genco::prelude::*;
497///
498/// let numbers = 3..=5;
499///
500/// let tokens: Tokens<()> = quote! {
501///     Your numbers are: $(for n in numbers join (, ) => $n).
502/// };
503///
504/// assert_eq!("Your numbers are: 3, 4, 5.", tokens.to_string()?);
505/// # Ok::<_, genco::fmt::Error>(())
506/// ```
507///
508/// <br>
509///
510/// # Conditionals
511///
512/// You can specify a conditional with `$(if <pattern> => <then>)` where
513/// `<pattern>` is an pattern or expression evaluating to a `bool`, and `<then>`
514/// is a quoted expressions.
515///
516/// It's also possible to specify a condition with an else branch, by using
517/// `$(if <pattern> { <then> } else { <else> })`. `<else>` is also a quoted
518/// expression.
519///
520/// ```
521/// use genco::prelude::*;
522///
523/// fn greeting(hello: bool, name: &str) -> Tokens<()> {
524///     quote!(Custom Greeting: $(if hello {
525///         Hello $name
526///     } else {
527///         Goodbye $name
528///     }))
529/// }
530///
531/// let tokens = greeting(true, "John");
532/// assert_eq!("Custom Greeting: Hello John", tokens.to_string()?);
533///
534/// let tokens = greeting(false, "John");
535/// assert_eq!("Custom Greeting: Goodbye John", tokens.to_string()?);
536/// # Ok::<_, genco::fmt::Error>(())
537/// ```
538///
539/// <br>
540///
541/// The `<else>` branch is optional, conditionals which do not have an else
542/// branch and evaluated to `false` won't produce any tokens:
543///
544/// ```
545/// use genco::prelude::*;
546///
547/// fn greeting(hello: bool, name: &str) -> Tokens<()> {
548///     quote!(Custom Greeting:$(if hello {
549///         $[' ']Hello $name
550///     }))
551/// }
552///
553/// let tokens = greeting(true, "John");
554/// assert_eq!("Custom Greeting: Hello John", tokens.to_string()?);
555///
556/// let tokens = greeting(false, "John");
557/// assert_eq!("Custom Greeting:", tokens.to_string()?);
558/// # Ok::<_, genco::fmt::Error>(())
559/// ```
560///
561/// <br>
562///
563/// # Match Statements
564///
565/// You can specify a match expression using `$(match <expr> { [<pattern> =>
566/// <quoted>,]* }`, where `<expr>` is an evaluated expression that is match
567/// against each subsequent `<pattern>`. If a pattern matches, the arm with the
568/// matching `<quoted>` block is evaluated.
569///
570/// ```
571/// use genco::prelude::*;
572///
573/// fn greeting(name: &str) -> Tokens<()> {
574///     quote!(Hello $(match name {
575///         "John" | "Jane" => $("Random Stranger"),
576///         other => $other,
577///     }))
578/// }
579///
580/// let tokens = greeting("John");
581/// assert_eq!("Hello Random Stranger", tokens.to_string()?);
582///
583/// let tokens = greeting("Mio");
584/// assert_eq!("Hello Mio", tokens.to_string()?);
585/// # Ok::<_, genco::fmt::Error>(())
586/// ```
587///
588/// If a match arm contains parenthesis (`=> (<quoted>)`), the expansion will be
589/// *whitespace sensitive*. Allowing leading and trailing whitespace to be
590/// preserved:
591///
592/// ```
593/// use genco::prelude::*;
594///
595/// fn greeting(name: &str) -> Tokens<()> {
596///     quote!(Hello$(match name {
597///         "John" | "Jane" => ( $("Random Stranger")),
598///         other => ( $other),
599///     }))
600/// }
601///
602/// let tokens = greeting("John");
603/// assert_eq!("Hello Random Stranger", tokens.to_string()?);
604///
605/// let tokens = greeting("Mio");
606/// assert_eq!("Hello Mio", tokens.to_string()?);
607/// # Ok::<_, genco::fmt::Error>(())
608/// ```
609///
610/// The following is an example with more complex matching:
611///
612/// ```
613/// use genco::prelude::*;
614///
615/// enum Greeting {
616///     Named(&'static str),
617///     Unknown,
618/// }
619///
620/// fn greeting(name: Greeting) -> Tokens<()> {
621///     quote!(Hello $(match name {
622///         Greeting::Named("John") | Greeting::Named("Jane") => $("Random Stranger"),
623///         Greeting::Named(other) => $other,
624///         Greeting::Unknown => $("Unknown Person"),
625///     }))
626/// }
627///
628/// let tokens = greeting(Greeting::Named("John"));
629/// assert_eq!("Hello Random Stranger", tokens.to_string()?);
630///
631/// let tokens = greeting(Greeting::Unknown);
632/// assert_eq!("Hello Unknown Person", tokens.to_string()?);
633///
634/// let tokens = greeting(Greeting::Named("Mio"));
635/// assert_eq!("Hello Mio", tokens.to_string()?);
636/// # Ok::<_, genco::fmt::Error>(())
637/// ```
638///
639/// <br>
640///
641/// # Variable assignment
642///
643/// You can use `$(let <binding> = <expr>)` to define variables with their value.
644/// This is useful within loops to compute values from iterator items.
645///
646/// ```
647/// use genco::prelude::*;
648///
649/// let names = ["A.B", "C.D"];
650///
651/// let tokens: Tokens<()> = quote! {
652///     $(for name in names =>
653///         $(let (first, second) = name.split_once('.').unwrap())
654///         $first and $second.
655///     )
656/// };
657/// assert_eq!("A and B.\nC and D.", tokens.to_string()?);
658/// # Ok::<_, genco::fmt::Error>(())
659/// ```
660///
661/// Variables can also be mutable:
662///
663/// ```
664/// use genco::prelude::*;
665/// let path = "A.B.C.D";
666///
667/// let tokens: Tokens<()> = quote! {
668///     $(let mut items = path.split('.'))
669///     $(if let Some(first) = items.next() =>
670///         First is $first
671///     )
672///     $(if let Some(second) = items.next() =>
673///         Second is $second
674///     )
675/// };
676///
677/// assert_eq!("First is A\nSecond is B", tokens.to_string()?);
678/// # Ok::<_, genco::fmt::Error>(())
679/// ```
680///
681/// <br>
682///
683/// # Scopes
684///
685/// You can use `$(ref <binding> { <expr> })` to gain access to the current
686/// token stream. This is an alternative to existing control flow operators if
687/// you want to run some custom code during evaluation which is otherwise not
688/// supported. This is called a *scope*.
689///
690/// For a more compact variant you can omit the braces with `$(ref <binding> =>
691/// <expr>)`.
692///
693/// ```
694/// use genco::prelude::*;
695///
696/// fn quote_greeting(surname: &str, lastname: Option<&str>) -> rust::Tokens {
697///     quote! {
698///         Hello $surname$(ref toks {
699///             if let Some(lastname) = lastname {
700///                 toks.space();
701///                 toks.append(lastname);
702///             }
703///         })
704///     }
705/// }
706///
707/// assert_eq!("Hello John", quote_greeting("John", None).to_string()?);
708/// assert_eq!("Hello John Doe", quote_greeting("John", Some("Doe")).to_string()?);
709/// # Ok::<_, genco::fmt::Error>(())
710/// ```
711///
712/// <br>
713///
714/// ## Whitespace Detection
715///
716/// The [`quote!`] macro has the following rules for dealing with indentation and
717/// spacing.
718///
719/// **Spaces** — Two tokens that are separated are spaced. Regardless of how
720/// many spaces there are between them. This can be controlled manually by
721/// inserting the [`$[' ']`][escape] escape sequence in the token stream.
722///
723/// ```
724/// use genco::prelude::*;
725///
726/// let tokens: rust::Tokens = quote! {
727///     fn     test()     {
728///         println!("Hello... ");
729///
730///         println!("World!");
731///     }
732/// };
733///
734/// assert_eq!(
735///     vec![
736///         "fn test() {",
737///         "    println!(\"Hello... \");",
738///         "",
739///         "    println!(\"World!\");",
740///         "}",
741///     ],
742///     tokens.to_file_vec()?,
743/// );
744/// # Ok::<_, genco::fmt::Error>(())
745/// ```
746///
747/// <br>
748///
749/// **Line breaking** — Line breaks are detected by leaving two empty lines
750/// between two tokens. This can be controlled manually by inserting the
751/// [`$['\n']`][escape] escape in the token stream.
752///
753/// ```
754/// use genco::prelude::*;
755///
756/// let tokens: rust::Tokens = quote! {
757///     fn test() {
758///         println!("Hello... ");
759///
760///
761///
762///         println!("World!");
763///     }
764/// };
765///
766/// assert_eq!(
767///     vec![
768///         "fn test() {",
769///         "    println!(\"Hello... \");",
770///         "",
771///         "    println!(\"World!\");",
772///         "}",
773///     ],
774///     tokens.to_file_vec()?,
775/// );
776/// # Ok::<_, genco::fmt::Error>(())
777/// ```
778///
779/// <br>
780///
781/// **Indentation** — Indentation is determined on a row-by-row basis. If a
782/// column is further in than the one on the preceeding row, it is indented *one
783/// level* deeper.
784///
785/// If a column starts shallower than a preceeding, non-whitespace only row, it
786/// will be matched against previously known indentation levels. Failure to
787/// match a previously known level is an error.
788///
789/// All indentations inserted during the macro will be unrolled at the end of
790/// it. So any trailing indentations will be matched by unindentations.
791///
792/// ```
793/// use genco::prelude::*;
794///
795/// let tokens: rust::Tokens = quote! {
796///     fn test() {
797///             println!("Hello... ");
798///
799///             println!("World!");
800///     }
801/// };
802///
803/// assert_eq!(
804///     vec![
805///         "fn test() {",
806///         "    println!(\"Hello... \");",
807///         "",
808///         "    println!(\"World!\");",
809///         "}",
810///     ],
811///     tokens.to_file_vec()?,
812/// );
813/// # Ok::<_, genco::fmt::Error>(())
814/// ```
815///
816/// Example showcasing an indentation mismatch:
817///
818/// ```,compile_fail
819/// use genco::prelude::*;
820///
821/// let tokens: rust::Tokens = quote! {
822///     fn test() {
823///             println!("Hello... ");
824///
825///         println!("World!");
826///     }
827/// };
828/// ```
829///
830/// ```text
831/// ---- src\lib.rs -  (line 150) stdout ----
832/// error: expected 4 less spaces of indentation
833/// --> src\lib.rs:157:9
834///    |
835/// 10 |         println!("World!");
836///    |         ^^^^^^^
837/// ```
838///
839/// [escape]: #escape-sequences
840pub use genco_macros::quote;
841
842/// Convenience macro for constructing a [`FormatInto`] implementation in-place.
843///
844/// Constructing [`FormatInto`] implementation instead of short lived [token
845/// streams] can be more beneficial for memory use and performance.
846///
847/// [`FormatInto`]: crate::tokens::FormatInto
848/// [token streams]: Tokens
849///
850/// # Comparison
851///
852/// In the below example, `f1` and `f2` are equivalent. In here [quote_fn!]
853/// simply makes it easier to build.
854///
855/// ```
856/// use genco::prelude::*;
857/// use genco::tokens::from_fn;
858///
859/// let f1 = from_fn(move |t| {
860///     quote_in!{ *t =>
861///         println!("Hello World");
862///     }
863/// });
864///
865/// let f2 = quote_fn!{
866///     println!("Hello World");
867/// };
868///
869/// let tokens: rust::Tokens = quote!{
870///     $f1
871///     $f2
872/// };
873///
874/// assert_eq!{
875///     vec![
876///         "println!(\"Hello World\");",
877///         "println!(\"Hello World\");",
878///     ],
879///     tokens.to_file_vec()?,
880/// };
881/// # Ok::<_, genco::fmt::Error>(())
882/// ```
883///
884/// # Examples which borrow
885///
886/// ```
887/// use genco::prelude::*;
888///
889/// fn greeting(name: &str) -> impl FormatInto<Rust> + '_ {
890///     quote_fn! {
891///         println!($[str](Hello $[const](name)))
892///     }
893/// }
894///
895/// fn advanced_greeting<'a>(first: &'a str, last: &'a str) -> impl FormatInto<Rust> + 'a {
896///     quote_fn! {
897///         println!($[str](Hello $[const](first) $[const](last)))
898///     }
899/// }
900///
901/// let tokens = quote! {
902///     $(greeting("Mio"));
903///     $(advanced_greeting("Jane", "Doe"));
904/// };
905///
906/// assert_eq!{
907///     vec![
908///         "println!(\"Hello Mio\");",
909///         "println!(\"Hello Jane Doe\");",
910///     ],
911///     tokens.to_file_vec()?
912/// };
913/// # Ok::<_, genco::fmt::Error>(())
914/// ```
915pub use genco_macros::quote_fn;
916
917/// Behaves the same as [`quote!`] while quoting into an existing token stream
918/// with `<target> => <quoted>`.
919///
920/// This macro takes a destination stream followed by an `=>` and the tokens to
921/// extend that stream with.
922///
923/// Note that it must be possible to borrow `<target>` mutably, so a reference
924/// like `&mut rust::Tokens` will have to be dereferenced when used with this
925/// macro.
926///
927/// ```
928/// # use genco::prelude::*;
929///
930/// # fn generate() -> rust::Tokens {
931/// let mut tokens = rust::Tokens::new();
932/// quote_in!(tokens => hello world);
933/// # tokens
934/// # }
935///
936/// fn generate_into(tokens: &mut rust::Tokens) {
937///     quote_in! { *tokens =>
938///         hello...
939///         world!
940///     };
941/// }
942/// ```
943///
944/// # Example
945///
946/// ```
947/// use genco::prelude::*;
948///
949/// let mut tokens = rust::Tokens::new();
950///
951/// quote_in! { tokens =>
952///     fn foo() -> u32 {
953///         42
954///     }
955/// }
956/// ```
957///
958/// # Use with scopes
959///
960/// [`quote_in!`] can be used inside of a [`quote!`] through [a scope].
961///
962/// ```
963/// use genco::prelude::*;
964///
965/// let tokens: rust::Tokens = quote! {
966///     fn foo(v: bool) -> u32 {
967///         $(ref out {
968///             quote_in! { *out =>
969///                 if v {
970///                     1
971///                 } else {
972///                     0
973///                 }
974///             }
975///         })
976///     }
977/// };
978/// ```
979///
980/// [a scope]: quote#scopes
981pub use genco_macros::quote_in;
982
983#[macro_use]
984mod macros;
985pub mod fmt;
986pub mod lang;
987pub mod prelude;
988pub mod tokens;
989#[doc(inline)]
990pub use self::tokens::Tokens;
991
992/// Private module used for macros.
993#[doc(hidden)]
994pub mod __priv {
995    use alloc::boxed::Box;
996
997    use crate::lang::Lang;
998    use crate::tokens::{from_fn, FormatInto};
999    use crate::tokens::{Item, ItemStr};
1000
1001    #[inline]
1002    pub const fn static_<L>(string: &'static str) -> Item<L>
1003    where
1004        L: Lang,
1005    {
1006        Item::static_(string)
1007    }
1008
1009    #[inline]
1010    pub const fn literal<L>(string: ItemStr) -> Item<L>
1011    where
1012        L: Lang,
1013    {
1014        Item::literal(string)
1015    }
1016
1017    #[inline]
1018    pub const fn indentation<L>(level: i16) -> Item<L>
1019    where
1020        L: Lang,
1021    {
1022        Item::indentation(level)
1023    }
1024
1025    #[inline]
1026    pub const fn push<L>() -> Item<L>
1027    where
1028        L: Lang,
1029    {
1030        Item::push()
1031    }
1032
1033    #[inline]
1034    pub const fn line<L>() -> Item<L>
1035    where
1036        L: Lang,
1037    {
1038        Item::line()
1039    }
1040
1041    #[inline]
1042    pub const fn space<L>() -> Item<L>
1043    where
1044        L: Lang,
1045    {
1046        Item::space()
1047    }
1048
1049    #[inline]
1050    pub const fn open_quote<L>(is_interpolation: bool) -> Item<L>
1051    where
1052        L: Lang,
1053    {
1054        Item::open_quote(is_interpolation)
1055    }
1056
1057    #[inline]
1058    pub const fn close_quote<L>() -> Item<L>
1059    where
1060        L: Lang,
1061    {
1062        Item::close_quote()
1063    }
1064
1065    #[inline]
1066    pub const fn open_eval<L>() -> Item<L>
1067    where
1068        L: Lang,
1069    {
1070        Item::open_eval()
1071    }
1072
1073    #[inline]
1074    pub const fn close_eval<L>() -> Item<L>
1075    where
1076        L: Lang,
1077    {
1078        Item::close_eval()
1079    }
1080
1081    /// Add a language item directly.
1082    ///
1083    /// This must only be used by the [`impl_lang!`] macro.
1084    ///
1085    /// [`impl_lang!`]: crate::impl_lang!
1086    #[doc(hidden)]
1087    #[inline]
1088    pub fn item<L>(item: L::Item) -> impl FormatInto<L>
1089    where
1090        L: Lang,
1091    {
1092        from_fn(|t| {
1093            t.lang_item(Box::new(item));
1094        })
1095    }
1096
1097    /// Register a language item directly.
1098    ///
1099    /// This must only be used by the [`impl_lang!`] macro.
1100    ///
1101    /// [`impl_lang!`]: crate::impl_lang!
1102    #[doc(hidden)]
1103    #[inline]
1104    pub fn register<L>(item: L::Item) -> impl FormatInto<L>
1105    where
1106        L: Lang,
1107    {
1108        from_fn(|t| {
1109            t.lang_item_register(Box::new(item));
1110        })
1111    }
1112}