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}