preinterpret/lib.rs
1//! # Preinterpet - The code generation toolkit
2//!
3//! [<img alt="github" src="https://img.shields.io/badge/github-dhedey/preinterpret-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dhedey/preinterpret)
4//! [<img alt="crates.io" src="https://img.shields.io/crates/v/preinterpret.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/preinterpret)
5//! [<img alt="Crates.io MSRV" src="https://img.shields.io/crates/msrv/preinterpret?style=for-the-badge&logo=rust&logoColor=green&color=green" height="20">](https://crates.io/crates/preinterpret)
6//! [<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-preinterpret-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/preinterpret)
7//! [<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dhedey/preinterpret/ci.yml?branch=main&style=for-the-badge" height="20">](https://github.com/dhedey/preinterpret/actions?query=branch%3Amain)
8//!
9//! <!--
10//! If updating this readme, please ensure that the lib.rs rustdoc is also updated.
11//! Copy the whole of this document to a new text file, replace `/n` with `\n//! ` prefix to each line, and paste into `lib.rs`
12//! -->
13//!
14//! This crate provides the `preinterpret!` macro, which works as a simple pre-processor to the token stream. It takes inspiration from and effectively combines the [quote](https://crates.io/crates/quote), [paste](https://crates.io/crates/paste) and [syn](https://crates.io/crates/syn) crates, to empower code generation authors and declarative macro writers, bringing:
15//!
16//! * **Heightened [readability](#readability)** - quote-like variable definition and substitution make it easier to work with code generation code.
17//! * **Heightened [expressivity](#expressivity)** - a toolkit of simple commands reduce boilerplate, and mitigate the need to build custom procedural macros in some cases.
18//! * **Heightened [simplicity](#simplicity)** - helping developers avoid the confusing corners [[1](https://veykril.github.io/tlborm/decl-macros/patterns/callbacks.html), [2](https://github.com/rust-lang/rust/issues/96184#issue-1207293401), [3](https://veykril.github.io/tlborm/decl-macros/minutiae/metavar-and-expansion.html), [4](https://veykril.github.io/tlborm/decl-macros/patterns/push-down-acc.html)] of declarative macro land.
19//!
20//! The `preinterpret!` macro can be used inside the output of a declarative macro, or by itself, functioning as a mini code generation tool all of its own.
21//!
22//! ```toml
23//! [dependencies]
24//! preinterpret = "0.2"
25//! ```
26//!
27//! ## User Guide
28//!
29//! Preinterpret works with its own very simple language, with two main syntax elements:
30//!
31//! * **Commands**: `[!command_name! ...input token stream...]` take an input token stream and output a token stream. There are a number of commands which cover a toolkit of useful functions.
32//! * **Variables**: `[!set! #var_name = token stream...]` defines a variable, and `#var_name` substitutes the variable into another command or the output.
33//!
34//! Commands can be nested intuitively. The input of all commands (except `[!raw! ...]`) are first interpreted before the command itself executes.
35//!
36//! ### Declarative macro example
37//!
38//! The following artificial example demonstrates how `preinterpret` can be integrate into declarative macros, and covers use of variables, idents and case conversion:
39//!
40//! ```rust
41//! macro_rules! create_my_type {
42//! (
43//! $(#[$attributes:meta])*
44//! $vis:vis struct $type_name:ident {
45//! $($field_name:ident: $inner_type:ident),* $(,)?
46//! }
47//! ) => {preinterpret::preinterpret! {
48//! [!set! #type_name = [!ident! My $type_name]]
49//!
50//! $(#[$attributes])*
51//! $vis struct #type_name {
52//! $($field_name: $inner_type,)*
53//! }
54//!
55//! impl #type_name {
56//! $(
57//! fn [!ident_snake! my_ $inner_type](&self) -> &$inner_type {
58//! &self.$field_name
59//! }
60//!
61//! fn [!ident_snake! my_ $inner_type _mut](&mut self) -> &mut $inner_type {
62//! &mut self.$field_name
63//! }
64//! )*
65//! }
66//! }}
67//! }
68//! create_my_type! {
69//! struct Struct {
70//! field0: String,
71//! field1: u64,
72//! }
73//! }
74//! assert_eq!(MyStruct { field0: "Hello".into(), field1: 21 }.my_string(), "Hello")
75//! ```
76//!
77//! ### Quick background on token streams and macros
78//!
79//! To properly understand how preinterpret works, we need to take a very brief detour into the language of macros.
80//!
81//! In Rust, the input and output to a macro is a [`TokenStream`](https://doc.rust-lang.org/proc_macro/enum.TokenStream.html). A `TokenStream` is simply an iterator of [`TokenTree`](https://doc.rust-lang.org/proc_macro/enum.TokenTree.html)s at a particular nesting level. A token tree is one of four things:
82//!
83//! * A [`Group`](https://doc.rust-lang.org/proc_macro/struct.Group.html) - typically `(..)`, `[..]` or `{..}`. It consists of a matched pair of brackets "[`Delimiter`s]` and an internal token stream. There is technically a [confusing](https://github.com/rust-lang/rust/issues/67062) fourth type of group, with transparent brackets; used to encapsulate declarative macro substitutions. This is purposefully ignored/flattened in pre-interpret.
84//! * An [`Ident`](https://doc.rust-lang.org/proc_macro/struct.Ident.html) - An unquoted string, used to identitied something named. Think `MyStruct`, or `do_work` or `my_module`.
85//! * A [`Punct`](https://doc.rust-lang.org/proc_macro/struct.Punct.html) - A single piece of punctuation. Think `!` or `:`.
86//! * A [`Literal`](https://doc.rust-lang.org/proc_macro/struct.Literal.html) - This includes string literals `"my string"`, char literals `'x'` and numeric literals `23` / `51u64`. Note that `true`/`false` are technically idents.
87//!
88//! When you return output from a macro, you are outputting back a token stream, which the compiler will interpret.
89//!
90//! Preinterpret commands take token streams as input, and return token streams as output.
91//!
92//! ### Migration from paste
93//!
94//! If migrating from [paste](https://crates.io/crates/paste), the main difference is that you need to specify _what kind of concatenated thing you want to create_. Paste tried to work this out magically from context, but sometimes got it wrong.
95//!
96//! In other words, you typically want to replace `[< ... >]` with `[!ident! ...]`, and sometimes `[!string! ...]` or `[!literal! ...]`:
97//! * To create type and function names, use `[!ident! My #preinterpret_type_name $macro_type_name]`, `[!ident_camel! ...]`, `[!ident_snake! ...]` or `[!ident_upper_snake! ...]`
98//! * For doc macros or concatenated strings, use `[!string! "My type is: " #type_name]`
99//! * If you're creating literals of some kind by concatenating parts together, use `[!literal! 32 u32]`
100//!
101//! For example:
102//!
103//! ```rust
104//! preinterpret::preinterpret! {
105//! [!set! #type_name = [!ident! HelloWorld]]
106//!
107//! struct #type_name;
108//!
109//! #[doc = [!string! "This type is called [`" #type_name "`]"]]
110//! impl #type_name {
111//! fn [!ident_snake! say_ #type_name]() -> &'static str {
112//! [!string! "It's time to say: " [!title! #type_name] "!"]
113//! }
114//! }
115//! }
116//! assert_eq!(HelloWorld::say_hello_world(), "It's time to say: Hello World!")
117//! ```
118//!
119//! ## Command List
120//!
121//! ### Special commands
122//!
123//! * `[!set! #foo = Hello]` followed by `[!set! #foo = #bar(World)]` sets the variable `#foo` to the token stream `Hello` and `#bar` to the token stream `Hello(World)`, and outputs no tokens. Using `#foo` or `#bar` later on will output the current value in the corresponding variable.
124//! * `[!raw! abc #abc [!ident! test]]` outputs its contents as-is, without any interpretation, giving the token stream `abc #abc [!ident! test]`.
125//! * `[!ignore! $foo]` ignores all of its content and outputs no tokens. It is useful to make a declarative macro loop over a meta-variable without outputting it into the resulting stream.
126//!
127//! ### Concatenate and convert commands
128//!
129//! Each of these commands functions in three steps:
130//! * Apply the interpreter to the token stream, which recursively executes preinterpret commands.
131//! * Convert each token of the resulting stream into a string, and concatenate these together. String and char literals are unquoted, and this process recurses into groups.
132//! * Apply some command-specific conversion.
133//!
134//! The following commands output idents:
135//!
136//! * `[!ident! X Y "Z"]` outputs the ident `XYZ`
137//! * `[!ident_camel! my hello_world]` outputs `MyHelloWorld`
138//! * `[!ident_snake! my_ HelloWorld]` outputs `my_hello_world`
139//! * `[!ident_upper_snake! my_ const Name]` outputs `MY_CONST_NAME`
140//!
141//! The `!literal!` command outputs any kind of literal, for example:
142//!
143//! * `[!literal! 31 u 32]` outputs the integer literal `31u32`
144//! * `[!literal! '"' hello '"']` outputs the string literal `"hello"`
145//!
146//! The following commands output strings, without dropping non-alphanumeric characters:
147//!
148//! * `[!string! X Y " " Z (Hello World)]` outputs `"XY Z(HelloWorld)"`
149//! * `[!upper! foo_bar]` outputs `"FOO_BAR"`
150//! * `[!lower! FooBar]` outputs `"foobar"`
151//! * `[!capitalize! fooBar]` outputs `"FooBar"`
152//! * `[!decapitalize! FooBar]` outputs `"fooBar"`
153//! * `[!insert_spaces! fooBar]` outputs `"foo Bar"`
154//!
155//! The following commands output strings, whilst also dropping non-alphanumeric characters:
156//!
157//! * `[!snake! FooBar]` and `[!lower_snake! FooBar]` are equivalent and output `"foo_bar"`
158//! * `[!upper_snake! FooBar]` outputs `"FOO_BAR"`
159//! * `[!camel! foo_bar]` and `[!upper_camel! foo_bar]` are equivalent and output `"FooBar"`. This filters out non-alphanumeric characters.
160//! * `[!lower_camel! foo_bar]` outputs `"fooBar"`
161//! * `[!kebab! fooBar]` outputs `"foo-bar"`
162//!
163//! > [!NOTE]
164//! >
165//! > These string conversion methods are designed to work intuitively across a wide class of input strings, by creating word boundaries when going from non-alphanumeric to alphanumeric, lowercase to uppercase, or uppercase to uppercase if the next character is lowercase.
166//! >
167//! > The case-conversion commands which drop non-alphanumeric characters can potentially break up grapheme clusters and can cause unintuitive behaviour
168//! > when used with complex unicode strings.
169//! >
170//! > A wide ranging set of tests covering behaviour are in [tests/string.rs](https://www.github.com/dhedey/preinterpret/blob/main/tests/string.rs).
171//!
172//! ## Motivation
173//!
174//! ### Readability
175//!
176//! The preinterpret syntax is intended to be immediately intuitive even for people not familiar with the crate. And it enables developers to make more readable macros:
177//!
178//! * Developers can name clear concepts in their macro output, and re-use them by name, decreasing code duplication.
179//! * Developers can use variables to subdivide logic inside the macro, without having to resort to creating lots of small, functional helper macros.
180//!
181//! These ideas are demonstrated with the following simple example:
182//!
183//! ```rust
184//! macro_rules! impl_marker_traits {
185//! {
186//! impl [
187//! // The marker traits to implement
188//! $($trait:ident),* $(,)?
189//! ] for $type_name:ident
190//! $(
191//! // Arbitrary (non-const) type generics
192//! < $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? $( = $deflt:tt)? ),+ >
193//! )?
194//! } => {preinterpret::preinterpret!{
195//! [!set! #impl_generics = $(< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)?]
196//! [!set! #type_generics = $(< $( $lt ),+ >)?]
197//! [!set! #my_type = $type_name #type_generics]
198//!
199//! $(
200//! // Output each marker trait for the type
201//! impl #impl_generics $trait for #my_type {}
202//! )*
203//! }}
204//! }
205//! trait MarkerTrait1 {}
206//! trait MarkerTrait2 {}
207//! struct MyType<T: Clone>(T);
208//! impl_marker_traits! {
209//! impl [MarkerTrait1, MarkerTrait2] for MyType<T: Clone>
210//! };
211//! ```
212//!
213//! ### Expressivity
214//!
215//! Preinterpret provides a suite of simple, composable commands to convert token streams, literals and idents. The full list is documented in the [Command List](#command-list) section.
216//!
217//! For example:
218//!
219//! ```rust
220//! macro_rules! create_struct_and_getters {
221//! (
222//! $name:ident { $($field:ident),* $(,)? }
223//! ) => {preinterpret::preinterpret!{
224//! // Define a struct with the given fields
225//! pub struct $name {
226//! $(
227//! $field: String,
228//! )*
229//! }
230//!
231//! impl $name {
232//! $(
233//! // Define get_X for each field X
234//! pub fn [!ident! get_ $field](&self) -> &str {
235//! &self.$field
236//! }
237//! )*
238//! }
239//! }}
240//! }
241//! create_struct_and_getters! {
242//! MyStruct { hello, world }
243//! }
244//! ```
245//!
246//! Variable assignment works intuitively with the `* + ?` expansion operators, allowing basic procedural logic, such as creation of loop counts and indices before [meta-variables](https://github.com/rust-lang/rust/issues/83527) are stabilized.
247//!
248//! For example:
249//! ```rust
250//! macro_rules! count_idents {
251//! {
252//! $($item: ident),*
253//! } => {preinterpret::preinterpret!{
254//! [!set! #current_index = 0usize]
255//! $(
256//! [!ignore! $item] // Loop over the items, but don't output them
257//! [!set! #current_index = #current_index + 1]
258//! )*
259//! [!set! #count = #current_index]
260//! #count
261//! }}
262//! }
263//! ```
264//!
265//! To quickly explain how this works, imagine we evaluate `count_idents!(a, b, c)`. As `count_idents!` is the most outer macro, it runs first, and expands into the following token stream:
266//!
267//! ```rust
268//! let count = preinterpret::preinterpret!{
269//! [!set! #current_index = 0usize]
270//! [!ignore! a]
271//! [!set! #current_index = #current_index + 1]
272//! [!ignore! = b]
273//! [!set! #current_index = #current_index + 1]
274//! [!ignore! = c]
275//! [!set! #current_index = #current_index + 1]
276//! [!set! #count = #current_index]
277//! #count
278//! };
279//! ```
280//!
281//! Now the `preinterpret!` macro runs, resulting in `#count` equal to the token stream `0usize + 1 + 1 + 1`.
282//! This will be improved in future releases by adding support for mathematical operations on integer literals.
283//!
284//! ### Simplicity
285//!
286//! Using preinterpret partially mitigates some common areas of confusion when writing declarative macros.
287//!
288//! #### Cartesian metavariable expansion errors
289//!
290//! Sometimes you wish to output some loop over one meta-variable, whilst inside the loop of a non-parent meta-variable - in other words, you expect to create a cartesian product across these variables. But the macro evaluator only supports zipping of meta-variables of the same length, and [gives an unhelpful error message](https://github.com/rust-lang/rust/issues/96184#issue-1207293401).
291//!
292//! The classical wisdom is to output an internal `macro_rules!` definition to handle the inner output of the cartesian product [as per this stack overflow post](https://stackoverflow.com/a/73543948), but this isn't very intuitive.
293//!
294//! Standard use of preinterpret avoids this problem entirely, as demonstrated by the first readability example. If written out natively without preinterpret, the iteration of the generics in `#impl_generics` and `#my_type` wouldn't be compatible with the iteration over `$trait`.
295//!
296//! #### Eager macro confusion
297//!
298//! User-defined macros are not eager - they take a token stream in, and return a token stream; and further macros can then execute in this token stream.
299//!
300//! But confusingly, some compiler built-in macros in the standard library (such as `format_args!`, `concat!`, `concat_idents!` and `include!`) don't work like this - they actually inspect their arguments, evaluate any macros inside eagerly, before then operating on the outputted tokens.
301//!
302//! Don't get me wrong - it's useful that you can nest `concat!` calls and `include!` calls - but the fact that these macros use the same syntax as "normal" macros but use different resolution behaviour can cause confusion to developers first learning about macros.
303//!
304//! Preinterpet commands also typically interpret their arguments eagerly and recursively, but it tries to be less confusing by:
305//! * Having a clear name (Preinterpet) which suggests eager pre-processing.
306//! * Using a different syntax `[!command! ...]` to macros to avoid confusion.
307//! * Taking on the functionality of the `concat!` and `concat_idents!` macros so they don't have to be used alongside other macros.
308//!
309//! #### The recursive macro paradigm shift
310//!
311//! To do anything particularly advanced with declarative macros, you end up needing to conjure up various functional macro helpers to partially apply or re-order grammars. This is quite a paradigm-shift from most rust code.
312//!
313//! In quite a few cases, preinterpret can allow developers to avoid writing these recursive helper macros entirely.
314//!
315//! #### Limitations with paste support
316//!
317//! The widely used [paste](https://crates.io/crates/paste) crate takes the approach of magically hiding the token types from the developer, by attempting to work out whether a pasted value should be an ident, string or literal.
318//!
319//! This works 95% of the time, but in other cases such as [in attributes](https://github.com/dtolnay/paste/issues/99#issue-1909928493), it can cause developer friction. This proved to be one of the motivating use cases for developing preinterpret.
320//!
321//! Preinterpret is more explicit about types, and doesn't have these issues:
322//!
323//! ```rust
324//! macro_rules! impl_new_type {
325//! {
326//! $vis:vis $my_type:ident($my_inner_type:ty)
327//! } => {preinterpret::preinterpret!{
328//! #[xyz(as_type = [!string! $my_inner_type])]
329//! $vis struct $my_type($my_inner_type);
330//! }}
331//! }
332//! ```
333//!
334//! ## Future Extension Possibilities
335//!
336//! ### Add github docs page / rust book
337//!
338//! Add a github docs page / rust book at this repository, to allow us to build out a suite of examples, like `serde` or the little book of macros.
339//!
340//! ### Destructuring / Parsing Syntax, and Declarative Macros 2.0
341//!
342//! I have a vision for having preinterpret effectively replace the use of declarative macros in the Rust ecosystem, by:
343//!
344//! * Enabling writing intuitive, procedural code, which feels a lot like normal rust
345//! * Exposing the power of [syn](https://crates.io/crates/syn) into this language, and preparing people to write procedural macros
346//!
347//! This would avoid pretty much all of the main the complexities of declarative macros:
348//!
349//! * The entirely lacking compile errors and auto-complete when it can't match tokens.
350//! * What the metavariable types mean as `:ty`, `:tt`, `:vis` and how to use them all... And the fact that, once matched, all but `tt` are opaque for future matching.
351//! * Having to learn a new paradigm of inverted thinking, which is pretty alien to rust.
352//! * The `macro_rules!` declaration itself - I can never remember which brackets to use...
353//!
354//! The idea is that we create two new tools:
355//!
356//! * The `parse` command which can be built up of compasable parse-helpers (mostly wrapping `syn` calls), intuitively handling lots of common patterns seen in code
357//! * Add control flow (`for`, `match` and the like) which runs lazily and declaratively, over the token stream primitive
358//!
359//! In more detail:
360//!
361//! * `[!parse! (<PARSE_DESTRUCTURING>) = (<INPUT>)]` is a more general `[!set!]` which acts like a `let <XX> = <YY> else { panic!() }`. It takes a `()`-wrapped parse destructuring on the left and a token stream as input on the right. Any `#x` in the parse definition acts as a binding rather than as a substitution. Parse operations look like `[<] Iterations are _not_ supported, but `[!optional] This will handled commas intelligently, and accept intelligent parse-helpers like:
362//! * `[<fields> { hello: #a, world?: #b }]` - which can parse `#x` in any order, cope with trailing commas, and permit fields on the RHS not on the LHS
363//! * `[<subfields> { hello: #a, world?: #b }]` - which can parse fields in any order, cope with trailing commas, and permit fields on the RHS not on the LHS
364//! * `[<item> { #ident, #impl_generics, ... }]` - which calls syn's parse item on the token
365//! * `[<ident> ...]`, `[<literal> ...]` and the like to parse idents / literals etc directly from the token stream (rather than token streams).
366//! * More tailored examples, such as `[<generics> { impl: #x, type: #y, where: #z }]` which uses syn to parse the generics, and then uses subfields on the result.
367//! * Possibly `[<group> #x]` to parse a group with no brackets, to avoid parser ambguity in some cases
368//! * Any complex logic (loops, matching), is delayed lazily until execution logic time - making it much more intuitive.
369//! * `[!for! (<PARSE_DESTRUCTURING>) in (<INPUT>) { ... }]` which operates like the rust `for` loop, and uses a parse destructuring on the left, and has support for optional commas between values
370//! * `[!match! (<INPUT>) => { (<CASE1>) => { ... }, (<CASE2>) => { ... }, (#fallback) => { ... } }]` which operates like a rust `match` expression, and can replace the function of the branches of declarative macro inputs.
371//! * `[!macro_rules! name!(<PARSE_DESTRUCTURING>) = { ... }]` which can define a declarative macro, but just parses its inputs as a token stream, and uses preinterpret for its heavy lifting.
372//!
373//! And then we can end up with syntax like the following:
374//!
375//! ```rust,ignore
376//! // =================================================
377//! // Hypothetical future syntax - not yet implemented!
378//! // =================================================
379//!
380//! // A simple macro can just take a token stream as input
381//! preinterpret::preinterpret! {
382//! [!macro_rules! my_macro!(#input) {
383//! [!for! (#trait for #type) in (#input) {
384//! impl #trait for #type
385//! }]
386//! }]
387//! }
388//!
389//! // Or can parse input - although loops are kept as a token stream and delegated
390//! // to explicit lazy iteration, allowing a more procedural code style,
391//! // and clearer compiler errors.
392//! preinterpret::preinterpret! {
393//! [!macro_rules! multi_impl_super_duper!(
394//! #type_list,
395//! ImplOptions [!fields! {
396//! hello: #hello,
397//! world?: #world (default "Default")
398//! }]
399//! ) = {
400//! [!for! (
401//! #type [!generics! { impl: #impl_generics, type: #type_generics }]
402//! ) in (#type_list) {
403//! impl<#impl_generics> SuperDuper for #type #type_generics {
404//! type Hello = #hello;
405//! type World = #world;
406//! }
407//! }]
408//! }]
409//! }
410//!
411//! preinterpret::preinterpret! {
412//! [!set! #input =
413//! MyTrait for MyType,
414//! MyTrait for MyType2,
415//! ]
416//!
417//! [!for! (#trait for #type) in (#input) {
418//! impl #trait for #type
419//! }]
420//! }
421//! ```
422//!
423//! ### Possible extension: Integer commands
424//!
425//! Each of these commands functions in three steps:
426//! * Apply the interpreter to the token stream, which recursively executes preinterpret commands.
427//! * Iterate over each token (recursing into groups), expecting each to be an integer literal.
428//! * Apply some command-specific mapping to this stream of integer literals, and output a single integer literal without its type suffix. The suffix can be added back manually if required with a wrapper such as `[!literal! [!add! 1 2] u64]`.
429//!
430//! Integer commands under consideration are:
431//!
432//! * `[!add! 5u64 9 32]` outputs `46`. It takes any number of integers and outputs their sum. The calculation operates in `u128` space.
433//! * `[!sub! 64u32 1u32]` outputs `63`. It takes two integers and outputs their difference. The calculation operates in `i128` space.
434//! * `[!mod! $length 2]` outputs `0` if `$length` is even, else `1`. It takes two integers `a` and `b`, and outputs `a mod b`.
435//!
436//! We also support the following assignment commands:
437//!
438//! * `[!increment! #i]` is shorthand for `[!set! #i = [!add! #i 1]]` and outputs no tokens.
439//!
440//! Even better - we could even support calculator-style expression interpretation:
441//!
442//! * `[!usize! (5 + 10) / mod(4, 2)]` outputs `7usize`
443//!
444//! ### Possible extension: User-defined commands
445//!
446//! * `[!define! [!my_command! <PARSE_DESTRUCTURING>] { <OUTPUT> }]`
447//!
448//! ### Possible extension: Boolean commands
449//!
450//! Each of these commands functions in three steps:
451//! * Apply the interpreter to the token stream, which recursively executes preinterpret commands.
452//! * Expects to read exactly two token trees (unless otherwise specified)
453//! * Apply some command-specific comparison, and outputs the boolean literal `true` or `false`.
454//!
455//! Comparison commands under consideration are:
456//! * `[!eq! #foo #bar]` outputs `true` if `#foo` and `#bar` are exactly the same token tree, via structural equality. For example:
457//! * `[!eq! (3 4) (3 4)]` outputs `true` because the token stream ignores spacing.
458//! * `[!eq! 1u64 1]` outputs `false` because these are different literals.
459//! * `[!lt! #foo #bar]` outputs `true` if `#foo` is an integer literal and less than `#bar`
460//! * `[!gt! #foo #bar]` outputs `true` if `#foo` is an integer literal and greater than `#bar`
461//! * `[!lte! #foo #bar]` outputs `true` if `#foo` is an integer literal and less than or equal to `#bar`
462//! * `[!gte! #foo #bar]` outputs `true` if `#foo` is an integer literal and greater than or equal to `#bar`
463//! * `[!not! #foo]` expects a single boolean literal, and outputs the negation of `#foo`
464//! * `[!str_contains! "needle" [!string! haystack]]` expects two string literals, and outputs `true` if the first string is a substring of the second string.
465//!
466//! ### Possible extension: Token stream commands
467//!
468//! * `[!skip! 4 from [#stream]]` reads and drops the first 4 token trees from the stream, and outputs the rest
469//! * `[!ungroup! (#stream)]` outputs `#stream`. It expects to receive a single group (i.e. wrapped in brackets), and unwraps it.
470//!
471//! ### Possible extension: Control flow commands
472//!
473//! #### If statement
474//!
475//! `[!if! #cond then { #a } else { #b }]` outputs `#a` if `#cond` is `true`, else `#b` if `#cond` is false.
476//!
477//! The `if` command works as follows:
478//! * It starts by only interpreting its first token tree, and expects to see a single `true` or `false` literal.
479//! * It then expects to reads an unintepreted `then` ident, following by a single `{ .. }` group, whose contents get interpreted and output only if the condition was `true`.
480//! * It optionally also reads an `else` ident and a by a single `{ .. }` group, whose contents get interpreted and output only if the condition was `false`.
481//!
482//! #### For loop
483//!
484//! * `[!for! #token_tree in [#stream] { ... }]`
485//!
486//! #### Goto and label
487//!
488//! * `[!label! loop_start]` - defines a label which can be returned to. Effectively, it takes a clones of the remaining token stream after the label in the interpreter.
489//! * `[!goto! loop_start]` - jumps to the last execution of `[!label! loop_start]`. It unrolls the preinterpret stack (dropping all unwritten token streams) until it finds a stackframe in which the interpreter has the defined label, and continues the token stream from there.
490//!
491//! ```rust,ignore
492//! // Hypothetical future syntax - not yet implemented!
493//! preinterpret::preinterpret!{
494//! [!set! #i = 0]
495//! [!label! loop]
496//! const [!ident! AB #i]: u8 = 0;
497//! [!increment! #i]
498//! [!if! [!lte! #i 100] then { [!goto! loop] }]
499//! }
500//! ```
501//!
502//! ### Possible extension: Eager expansion of macros
503//!
504//! When [eager expansion of macros returning literals](https://github.com/rust-lang/rust/issues/90765) is stabilized, it would be nice to include a command to do that, which could be used to include code, for example: `[!expand_literal_macros! include!("my-poem.txt")]`.
505//!
506//! ### Possible extension: Explicit parsing feature to enable syn
507//!
508//! The heavy `syn` library is (in basic preinterpret) only needed for literal parsing, and error conversion into compile errors.
509//!
510//! We could add a parsing feature to speed up compile times a lot for stacks which don't need the parsing functionality.
511mod command;
512mod commands;
513mod internal_prelude;
514mod interpreter;
515mod parsing;
516mod string_conversion;
517
518use internal_prelude::*;
519
520/// Runs a simple interpeter over the token stream, allowing for variable assignment and substitution,
521/// and a toolkit of commands to simplify code generation.
522///
523/// Commands look like `[!command! arguments as token stream here]` and can be nested.
524///
525/// ## Command cheat sheet
526/// * `[!set! #foo = ...]` set a variable to the provided token stream
527/// * `#foo` outputs the variable's saved token stream
528/// * `[!ident! ...]` outputs an ident from parsing the concatenated token stream
529/// * `[!ident_camel! ...]` outputs an UpperCamelCased ident from parsing the concatenated token stream
530/// * `[!ident_snake! ...]` outputs a lower_snake_cased ident from parsing the concatenated token stream
531/// * `[!ident_upper_snake! ...]` outputs an UPPER_SNAKE_CASED ident from parsing the concatenated token stream
532/// * `[!string! ...]` outputs the concatenated token stream
533/// * `[!literal! ..]` outputs a literal from parsing the concatenated token stream
534/// * `#[doc = [!string! "My documentation is for " #my_type "."]]` can be used to create documentation strings
535///
536/// See the [crate-level documentation](crate) for full details.
537#[proc_macro]
538pub fn preinterpret(token_stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
539 interpret(proc_macro2::TokenStream::from(token_stream))
540 .unwrap_or_else(|err| err.to_compile_error())
541 .into()
542}
543
544// This is the recommended way to run the doc tests in the readme
545#[doc = include_str!("../README.md")]
546#[cfg(doctest)] // Don't actually export this!
547#[proc_macro]
548pub fn readme_doctests(token_stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
549 unimplemented!()
550}