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}