Skip to main content

tokel_std/
structure.rs

1//! Structural boundary and grouping Tokel [`Transformer`]s.
2//!
3//! This module provides transformers for modifying the structural hierarchy
4//! and boundaries of token streams.
5//!
6//! # Available Transformers
7//!
8//! | Transformer       | Argument Type           | Description |
9//! |-------------------|-------------------------|-------------|
10//! | [`Flatten`]       | [`syn::parse::Nothing`] | Recursively removes all `()`, `{}`, and `[]` boundaries, flattening into a 1D stream. |
11//! | [`Encapsulate`]   | [`EncapsulateGroup`]    | Wraps the entire input stream inside the delimiter type of the provided argument. |
12//!
13//! # Argument Types
14//!
15//! * [`syn::parse::Nothing`] - No argument is required.
16//! * [`EncapsulateGroup`] - A single, empty token group (e.g., `()`, `{}`, or `[]`) that specifies the target encapsulation delimiter.
17//!
18//! # Examples
19//!
20//! **Basic Usage:**
21//! * `[< (()) [[Hello]] ([{ AA }]) >]:flatten` -> `Hello AA`
22//! * `[< Hello >]:encapsulate[[()]]` -> `(Hello)`
23//!
24//! # Remarks
25//!
26//! * [`Flatten`] recursively traverses all nested groups within the token stream and extracts their inner contents, resulting in a single, flat, one-dimensional token sequence.
27//! * [`Encapsulate`] takes the entire evaluated input stream and places it directly inside a new group matching the delimiter provided in the argument.
28
29use std::iter;
30
31use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
32
33use syn::parse::{Parse, ParseStream};
34
35use tokel_engine::prelude::{Pass, Registry, Transformer};
36
37/// Recursively removes all `()`, `{}`, and `[]` boundaries, flattening into a 1D stream.
38///
39/// # Arguments
40///
41/// This does not take any argument.
42///
43/// # Example
44///
45/// * `[< (()) [[Hello]] ([{ AA }]) >]:flatten` -> `Hello AA`
46#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
47pub struct Flatten;
48
49impl Pass for Flatten {
50    type Argument = syn::parse::Nothing;
51
52    fn through(&mut self, input: TokenStream, _: Self::Argument) -> syn::Result<TokenStream> {
53        /// A recursive function that does the flattening on token groups.
54        fn flatten(target_stream: TokenStream) -> TokenStream {
55            let mut target_output = TokenStream::new();
56
57            for target_tree in target_stream {
58                match target_tree {
59                    TokenTree::Group(target_group) => {
60                        target_output.extend(flatten(target_group.stream()))
61                    }
62                    flat_tree => target_output.extend(iter::once(flat_tree)),
63                }
64            }
65
66            target_output
67        }
68
69        Ok(flatten(input))
70    }
71}
72
73/// The argument type used for the [`Encapsulate`] pass.
74///
75/// This represents a single delimiter to use for the encapsulation.
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub struct EncapsulateGroup(Delimiter);
78
79impl Parse for EncapsulateGroup {
80    fn parse(input: ParseStream) -> syn::Result<Self> {
81        let group = input.parse::<Group>()?;
82
83        let _: [syn::parse::Nothing; 2] = [syn::parse2(group.stream())?, input.parse()?];
84
85        Ok(Self(group.delimiter()))
86    }
87}
88
89/// Wraps the entire input stream in the delimiter type of the provided argument [`Group`].
90///
91/// # Arguments
92///
93/// This takes a singular, empty token group with the delimiter to encapsulate the input stream in.
94///
95/// # Example
96///
97/// * `[< Hello >]:encapsulate[[()]]` -> `(Hello)`
98#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
99pub struct Encapsulate;
100
101impl Pass for Encapsulate {
102    type Argument = EncapsulateGroup;
103
104    fn through(
105        &mut self,
106        stream: TokenStream,
107        EncapsulateGroup(delimiter): Self::Argument,
108    ) -> syn::Result<TokenStream> {
109        Ok(iter::once(TokenTree::Group(Group::new(delimiter, stream))).collect::<TokenStream>())
110    }
111}
112
113/// Inserts all `structure`-related [`Transformer`]s into the specified [`Registry`].
114///
115/// # Errors
116///
117/// This will fail if at least one standard `structure`-related [`Transformer`] is already present by-name in the [`Registry`].
118///
119/// On failure, there is no guarantee that other non-colliding transformers have not been registered.
120#[inline]
121pub fn register(registry: &mut Registry) -> Result<(), Box<dyn Transformer>> {
122    registry
123        .try_insert("flatten", Flatten)
124        .map_err(Box::new)
125        .map_err(|target_value| target_value as Box<dyn Transformer>)?;
126
127    registry
128        .try_insert("encapsulate", Encapsulate)
129        .map_err(Box::new)
130        .map_err(|target_value| target_value as Box<dyn Transformer>)?;
131
132    Ok(())
133}