macros_utils/
repr.rs

1use proc_macro2::{Spacing, Span};
2use quote::quote;
3
4use crate::{tokens::LiteralKind, Delimiter, MacroStream, ParserOutput, Pattern, Token};
5
6/// The representation of an item as tokens to recreate it.
7pub trait Repr {
8    fn repr(&self, name: &str) -> MacroStream;
9}
10
11impl Repr for Token {
12    fn repr(&self, name: &str) -> MacroStream {
13        match self {
14            Self::Group {
15                delimiter,
16                stream,
17                span,
18            } => {
19                let delimiter = delimiter.repr(name);
20                let stream = stream.repr(name);
21                let span = span.repr(name);
22                quote! {
23                    macros_utils::Token::Group {
24                        delimiter: #delimiter,
25                        stream: #stream,
26                        span: #span,
27                    }
28                }
29            },
30            Self::Ident { name: n, span } => {
31                let span = span.repr(name);
32                quote! {
33                    macros_utils::Token::Ident {
34                        name: #n.to_string(),
35                        span: #span,
36                    }
37                }
38            },
39            Self::Literal {
40                kind,
41                value,
42                span,
43                suffix,
44                ..
45            } => {
46                let kind = kind.repr(name);
47                let span = span.repr(name);
48                quote! {
49                    macros_utils::Token::Literal {
50                        kind: #kind,
51                        value: #value.to_string(),
52                        span: #span,
53                        suffix: #suffix.to_string(),
54                        token: None,
55                    }
56                }
57            },
58            Self::Punctuation {
59                value,
60                spacing,
61                span,
62            } => {
63                let spacing = spacing.repr(name);
64                let span = span.repr(name);
65                quote! {
66                    macros_utils::Token::Punctuation {
67                        value: #value,
68                        spacing: #spacing,
69                        span: #span,
70                    }
71                }
72            },
73        }
74        .into()
75    }
76}
77
78impl Repr for Delimiter {
79    fn repr(&self, _: &str) -> MacroStream {
80        match self {
81            Delimiter::Brace => quote! { macros_utils::Delimiter::Brace },
82            Delimiter::Bracket => quote! { macros_utils::Delimiter::Bracket },
83            Delimiter::Parenthesis => quote! { macros_utils::Delimiter::Parenthesis },
84            Delimiter::None => quote! { macros_utils::Delimiter::None },
85        }
86        .into()
87    }
88}
89
90impl Repr for MacroStream {
91    fn repr(&self, name: &str) -> MacroStream {
92        let tokens = self.stream.iter().map(|token| token.repr(name));
93        quote! {
94            macros_utils::MacroStream::new(vec![
95                #(#tokens),*
96            ])
97        }
98        .into()
99    }
100}
101
102impl Repr for Span {
103    fn repr(&self, _: &str) -> MacroStream {
104        quote! {
105            macros_utils::call_site()
106        }
107        .into()
108    }
109}
110
111impl Repr for LiteralKind {
112    fn repr(&self, _: &str) -> MacroStream {
113        match self {
114            Self::Byte => quote! { macros_utils::LiteralKind::Byte },
115            Self::Char => quote! { macros_utils::LiteralKind::Char },
116            Self::Float => quote! { macros_utils::LiteralKind::Float },
117            Self::Integer => quote! { macros_utils::LiteralKind::Integer },
118            Self::Str => quote! { macros_utils::LiteralKind::Str },
119            Self::StrRaw(h) => quote! { macros_utils::LiteralKind::StrRaw(#h) },
120            Self::ByteStr => quote! { macros_utils::LiteralKind::ByteStr },
121            Self::ByteStrRaw(h) => quote! { macros_utils::LiteralKind::ByteStrRaw(#h) },
122        }
123        .into()
124    }
125}
126
127impl Repr for Spacing {
128    fn repr(&self, _: &str) -> MacroStream {
129        match self {
130            Self::Alone => quote! { macros_utils::Spacing::Alone },
131            Self::Joint => quote! { macros_utils::Spacing::Joint },
132        }
133        .into()
134    }
135}
136
137impl<T> Repr for Pattern<T>
138where
139    T: ToOwned<Owned = T> + ParserOutput,
140{
141    fn repr(&self, name: &str) -> MacroStream {
142        let type_name = Token::Ident {
143            name: name.to_string(),
144            span: Span::call_site(),
145        };
146        match self {
147            Self::Any => quote! { macros_utils::Pattern::<#type_name>::Any },
148            Self::Choice(patterns) => {
149                let patterns = patterns.repr(name);
150                quote! {
151                    macros_utils::Pattern::<#type_name>::Choice(#patterns)
152                }
153            },
154            Self::Group(delimiter, pattern) => {
155                let delimiter = delimiter.repr(name);
156                let patterns = pattern.repr(name);
157                quote! {
158                    macros_utils::Pattern::<#type_name>::Group(#delimiter, #patterns)
159                }
160            },
161            Self::OneOrMore(pattern, greedy) => {
162                let pattern = pattern.repr(name);
163                quote! {
164                    macros_utils::Pattern::<#type_name>::OneOrMore(#pattern, #greedy)
165                }
166            },
167            Self::Optional(pattern) => {
168                let pattern = pattern.repr(name);
169                quote! {
170                    macros_utils::Pattern::<#type_name>::Optional(#pattern)
171                }
172            },
173            Self::Parameter(pattern, parameter) => {
174                let pattern = pattern.repr(name);
175                quote! {
176                    macros_utils::Pattern::<#type_name>::Parameter(#pattern, #parameter.into())
177                }
178            },
179            Self::Token(token) => {
180                let token = token.repr(name);
181                quote! {
182                    macros_utils::Pattern::<#type_name>::Token(#token)
183                }
184            },
185            Self::Validator(stream, _) => {
186                let func = match stream {
187                    Some(s) => quote! { Some({#s}) },
188                    None => quote! { None },
189                };
190                quote! {
191                    macros_utils::Pattern::<#type_name>::Validator(None, #func)
192                }
193            },
194            Self::ZeroOrMore(pattern, greedy) => {
195                let pattern = pattern.repr(name);
196                quote! {
197                    macros_utils::Pattern::<#type_name>::ZeroOrMore(#pattern, #greedy)
198                }
199            },
200        }
201        .into()
202    }
203}
204
205impl<T> Repr for Vec<T>
206where
207    T: Repr,
208{
209    fn repr(&self, name: &str) -> MacroStream {
210        let tokens = self.iter().map(|token| token.repr(name));
211        quote! {
212            vec![
213                #(#tokens),*
214            ]
215        }
216        .into()
217    }
218}
219
220impl<T> Repr for Option<T>
221where
222    T: Repr,
223{
224    fn repr(&self, name: &str) -> MacroStream {
225        match self {
226            Some(value) => {
227                let value = value.repr(name);
228                quote! {
229                    Some(#value)
230                }
231            },
232            None => quote! { None },
233        }
234        .into()
235    }
236}
237
238impl<T> Repr for &T
239where
240    T: Repr,
241{
242    fn repr(&self, name: &str) -> MacroStream {
243        (*self).repr(name)
244    }
245}