unsynn/
group.rs

1//! Groups are a way to group tokens together. They are used to represent the contents between
2//! `()`, `{}`, `[]` or no delimiters at all.  This module provides parser implementations for
3//! opaque group types with defined delimiters and the [`GroupContaining`] types that parses the
4//! surrounding delimiters and content of a group type.
5
6#![allow(clippy::module_name_repetitions)]
7
8#[cfg(feature = "proc_macro2")]
9pub use proc_macro2::Delimiter;
10
11#[cfg(not(feature = "proc_macro2"))]
12pub use proc_macro::Delimiter;
13
14use crate::{
15    private, Error, Group, Parse, Parser, Result, ToTokens, TokenIter, TokenStream, TokenTree,
16};
17
18// Import the helper function from fundamental module
19use crate::fundamental::count_tokens_recursive;
20
21macro_rules! make_group {
22    ($($name:ident: $delimiter:ident);* $(;)?) => {
23        $(
24            #[doc = stringify!(A opaque group of tokens within a $delimiter)]
25            #[derive(Debug, Clone)]
26            pub struct $name(pub Group);
27
28            impl From<$name> for Group {
29                #[inline]
30                fn from(group: $name) -> Self {
31                    group.0
32                }
33            }
34
35            impl Parser for $name {
36                fn parser(tokens: &mut TokenIter) -> Result<Self> {
37                    match tokens.next() {
38                        Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::$delimiter => {
39                            // Count tokens inside the group and advance the shadow counter
40                            let nested_count = count_tokens_recursive(group.stream());
41                            tokens.add(nested_count);
42                            Ok(Self(group))
43                        }
44                        at => Error::unexpected_token(at, tokens),
45                    }
46                }
47            }
48
49            impl ToTokens for $name {
50                fn to_tokens(&self, tokens: &mut TokenStream) {
51                    self.0.to_tokens(tokens);
52                }
53            }
54
55            impl private::Sealed for $name {}
56
57            impl GroupDelimiter for $name {
58                fn delimiter(&self) -> Delimiter {
59                    Delimiter::$delimiter
60                }
61            }
62
63            impl From<$name> for TokenTree {
64                fn from(group: $name) -> Self {
65                    group.0.into()
66                }
67            }
68        )*
69    };
70}
71
72make_group! {
73    ParenthesisGroup: Parenthesis;
74    BraceGroup: Brace;
75    BracketGroup: Bracket;
76    NoneGroup: None;
77}
78
79#[test]
80fn test_bracegroup_into_tt() {
81    let mut token_iter = "{a b c}".to_token_iter();
82    let group = BraceGroup::parse(&mut token_iter).unwrap();
83    let _: TokenTree = group.into();
84}
85
86/// Access to the surrounding `Delimiter` of a `GroupContaining` and its variants.
87pub trait GroupDelimiter: private::Sealed {
88    /// The surrounding `Delimiter` of the group.
89    fn delimiter(&self) -> Delimiter;
90}
91
92/// Any kind of Group `G` with parseable content `C`.  The content `C` must parse exhaustive,
93/// an [`EndOfStream`](crate::EndOfStream) is automatically implied.
94#[derive(Clone)]
95pub struct GroupContaining<C> {
96    /// The delimiters around the group.
97    pub delimiter: Delimiter,
98    /// The content of the group.
99    pub content: C,
100}
101
102impl<C> GroupContaining<C> {
103    /// Create a new `GroupContaining` instance.
104    ///
105    /// # Example
106    ///
107    /// ```
108    /// # use unsynn::*;
109    ///
110    /// let group = GroupContaining::new(
111    ///     Delimiter::Parenthesis,
112    ///     Literal::i32_unsuffixed(123),
113    /// );
114    /// # assert_tokens_eq!(group, "(123)");
115    /// ```
116    pub const fn new(delimiter: Delimiter, content: C) -> Self {
117        Self { delimiter, content }
118    }
119}
120
121impl<C: Parse> Parser for GroupContaining<C> {
122    fn parser(tokens: &mut TokenIter) -> Result<Self> {
123        let group = Group::parser(tokens)?;
124        let delimiter = group.delimiter();
125
126        let content = tokens.parse_group::<C>(group.stream())?;
127
128        Ok(Self { delimiter, content })
129    }
130}
131
132impl<C: ToTokens> ToTokens for GroupContaining<C> {
133    fn to_tokens(&self, tokens: &mut TokenStream) {
134        Group::new(self.delimiter, self.content.to_token_stream()).to_tokens(tokens);
135    }
136}
137
138#[mutants::skip]
139impl<C: std::fmt::Debug> std::fmt::Debug for GroupContaining<C> {
140    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
141        f.debug_struct(&format!("GroupContaining<{}>", std::any::type_name::<C>()))
142            .field("delimiter", &self.delimiter)
143            .field("content", &self.content)
144            .finish()
145    }
146}
147
148impl<C> private::Sealed for GroupContaining<C> {}
149
150impl<C> GroupDelimiter for GroupContaining<C> {
151    fn delimiter(&self) -> Delimiter {
152        self.delimiter
153    }
154}
155
156impl<C: ToTokens> From<GroupContaining<C>> for TokenTree {
157    fn from(group: GroupContaining<C>) -> Self {
158        Group::new(group.delimiter(), group.content.to_token_stream()).into()
159    }
160}
161
162#[test]
163fn test_groupcontaining_into_tt() {
164    let mut token_iter = "{a b c}".to_token_iter();
165    let group = GroupContaining::<TokenStream>::parse(&mut token_iter).unwrap();
166    let _: TokenTree = group.into();
167}
168
169macro_rules! make_group_containing {
170    ($($name:ident: $delimiter:ident);* $(;)?) => {
171        $(
172            #[doc = stringify!(Parseable content within a $delimiter)]
173            #[derive(Clone)]
174            pub struct $name<C>{
175                /// The inner content of the group.
176                pub content: C
177            }
178
179            impl<C> $name<C> {
180                #[doc = stringify!(create a new $name instance)]
181                pub const fn new(content: C) -> Self {
182                    Self{content}
183                }
184            }
185
186            impl<C: Parse> Parser for $name<C> {
187                fn parser(tokens: &mut TokenIter) -> Result<Self> {
188                    match tokens.next() {
189                        Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::$delimiter => {
190                            let content = tokens.parse_group::<C>(group.stream())?;
191                            Ok(Self{content})
192                        }
193                        at => Error::unexpected_token(at, tokens),
194                    }
195                }
196            }
197
198            impl<C: ToTokens> ToTokens for $name<C> {
199                fn to_tokens(&self, tokens: &mut TokenStream) {
200                    Group::new(Delimiter::$delimiter, self.content.to_token_stream()).to_tokens(tokens);
201                }
202            }
203
204            impl<C: std::fmt::Debug> std::fmt::Debug
205                for $name<C>
206            {
207                fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
208                    f.debug_tuple(&format!(
209                        stringify!($name<{}>),
210                        std::any::type_name::<C>()
211                    ))
212                     .field(&self.content)
213                     .finish()
214                }
215            }
216
217            impl<C> private::Sealed for $name<C> {}
218
219            impl<C> GroupDelimiter for $name<C> {
220                fn delimiter(&self) -> Delimiter {
221                    Delimiter::$delimiter
222                }
223            }
224
225            impl<C: ToTokens> From<$name<C>> for TokenTree {
226                fn from(group: $name<C>) -> Self {
227                    Group::new(Delimiter::$delimiter, group.content.to_token_stream()).into()
228                }
229            }
230        )*
231    };
232}
233
234make_group_containing! {
235    ParenthesisGroupContaining: Parenthesis;
236    BraceGroupContaining: Brace;
237    BracketGroupContaining: Bracket;
238    NoneGroupContaining: None;
239}
240
241#[test]
242fn test_bracegroupcontaining_into_tt() {
243    let mut token_iter = "{a b c}".to_token_iter();
244    let group = BraceGroupContaining::<TokenStream>::parse(&mut token_iter).unwrap();
245    let _: TokenTree = group.into();
246}