1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 use proc_macro::TokenStream;
16 use proc_macro2::Ident;
17 use pw_format::macros::{
18 generate, generate_core_fmt, generate_printf, Arg, CoreFmtFormatMacroGenerator,
19 CoreFmtFormatStringParser, FormatAndArgsFlavor, FormatMacroGenerator, FormatParams,
20 FormatStringParser, PrintfFormatMacroGenerator, PrintfFormatStringFragment,
21 PrintfFormatStringParser, Result,
22 };
23 use quote::{quote, ToTokens};
24 use syn::parse_macro_input;
25
26 type TokenStream2 = proc_macro2::TokenStream;
27
28 // Generator for testing `generate()`.
29 struct TestGenerator {
30 code_fragments: Vec<TokenStream2>,
31 }
32
33 impl TestGenerator {
new() -> Self34 pub fn new() -> Self {
35 Self {
36 code_fragments: Vec::new(),
37 }
38 }
39 }
40
41 impl FormatMacroGenerator for TestGenerator {
finalize(self) -> Result<TokenStream2>42 fn finalize(self) -> Result<TokenStream2> {
43 let code_fragments = self.code_fragments;
44
45 Ok(quote! {
46 {
47 use pw_format_test_macros_test::TestGeneratorOps;
48 let mut ops = Vec::new();
49 #(#code_fragments);*;
50 ops.push(TestGeneratorOps::Finalize);
51 ops
52 }
53 })
54 }
55
string_fragment(&mut self, string: &str) -> Result<()>56 fn string_fragment(&mut self, string: &str) -> Result<()> {
57 self.code_fragments.push(quote! {
58 ops.push(TestGeneratorOps::StringFragment(#string.to_string()));
59 });
60 Ok(())
61 }
62
63 // This example ignores display type and width.
integer_conversion( &mut self, params: &FormatParams, signed: bool, type_width: u8, expression: Arg, ) -> Result<()>64 fn integer_conversion(
65 &mut self,
66 params: &FormatParams,
67 signed: bool,
68 type_width: u8, // in bits
69 expression: Arg,
70 ) -> Result<()> {
71 let expression = format!("{}", expression.to_token_stream());
72 self.code_fragments.push(quote! {
73 ops.push(TestGeneratorOps::IntegerConversion{
74 params: #params,
75 signed: #signed,
76 type_width: #type_width,
77 arg: #expression.to_string(),
78 });
79 });
80 Ok(())
81 }
82
string_conversion(&mut self, expression: Arg) -> Result<()>83 fn string_conversion(&mut self, expression: Arg) -> Result<()> {
84 let expression = format!("{}", expression.to_token_stream());
85 self.code_fragments.push(quote! {
86 ops.push(TestGeneratorOps::StringConversion(#expression.to_string()));
87 });
88 Ok(())
89 }
90
char_conversion(&mut self, expression: Arg) -> Result<()>91 fn char_conversion(&mut self, expression: Arg) -> Result<()> {
92 let expression = format!("{}", expression.to_token_stream());
93 self.code_fragments.push(quote! {
94 ops.push(TestGeneratorOps::CharConversion(#expression.to_string()));
95 });
96 Ok(())
97 }
98
untyped_conversion(&mut self, expression: Arg, _params: &FormatParams) -> Result<()>99 fn untyped_conversion(&mut self, expression: Arg, _params: &FormatParams) -> Result<()> {
100 let expression = format!("{}", expression.to_token_stream());
101 self.code_fragments.push(quote! {
102 ops.push(TestGeneratorOps::UntypedConversion(#expression.to_string()));
103 });
104 Ok(())
105 }
106 }
107
generator_test_macro_impl<T: FormatStringParser>(tokens: TokenStream) -> TokenStream108 fn generator_test_macro_impl<T: FormatStringParser>(tokens: TokenStream) -> TokenStream {
109 let format_and_args = parse_macro_input!(tokens as FormatAndArgsFlavor<T>);
110 let generator = TestGenerator::new();
111 match generate(generator, format_and_args.into()) {
112 Ok(token_stream) => token_stream.into(),
113 Err(e) => e.to_compile_error().into(),
114 }
115 }
116
117 #[proc_macro]
printf_format_generator_test_macro(tokens: TokenStream) -> TokenStream118 pub fn printf_format_generator_test_macro(tokens: TokenStream) -> TokenStream {
119 generator_test_macro_impl::<PrintfFormatStringParser>(tokens)
120 }
121
122 #[proc_macro]
core_fmt_format_generator_test_macro(tokens: TokenStream) -> TokenStream123 pub fn core_fmt_format_generator_test_macro(tokens: TokenStream) -> TokenStream {
124 generator_test_macro_impl::<CoreFmtFormatStringParser>(tokens)
125 }
126
127 // Generator for testing `generate_printf()`. Allows control over the return
128 // value of the conversion functions.
129 struct PrintfTestGenerator {
130 code_fragments: Vec<TokenStream2>,
131 integer_specifier_override: Option<String>,
132 string_specifier_override: Option<String>,
133 char_specifier_override: Option<String>,
134 }
135
136 impl PrintfTestGenerator {
new() -> Self137 pub fn new() -> Self {
138 Self {
139 code_fragments: Vec::new(),
140 integer_specifier_override: None,
141 string_specifier_override: None,
142 char_specifier_override: None,
143 }
144 }
145
with_integer_specifier(mut self, specifier: &str) -> Self146 pub fn with_integer_specifier(mut self, specifier: &str) -> Self {
147 self.integer_specifier_override = Some(specifier.to_string());
148 self
149 }
150
with_string_specifier(mut self, specifier: &str) -> Self151 pub fn with_string_specifier(mut self, specifier: &str) -> Self {
152 self.string_specifier_override = Some(specifier.to_string());
153 self
154 }
155
with_char_specifier(mut self, specifier: &str) -> Self156 pub fn with_char_specifier(mut self, specifier: &str) -> Self {
157 self.char_specifier_override = Some(specifier.to_string());
158 self
159 }
160 }
161
162 impl PrintfFormatMacroGenerator for PrintfTestGenerator {
finalize( self, format_string_fragments: &[PrintfFormatStringFragment], ) -> Result<TokenStream2>163 fn finalize(
164 self,
165 format_string_fragments: &[PrintfFormatStringFragment],
166 ) -> Result<TokenStream2> {
167 // Create locally scoped alias so we can refer to them in `quote!()`.
168 let code_fragments = self.code_fragments;
169 let format_string_pieces: Vec<_> = format_string_fragments
170 .iter()
171 .map(|fragment| fragment.as_token_stream("pw_format_core"))
172 .collect::<Result<Vec<_>>>()?;
173
174 Ok(quote! {
175 {
176 use pw_format_test_macros_test::PrintfTestGeneratorOps;
177 let mut ops = Vec::new();
178 let format_string = pw_bytes::concat_static_strs!(#(#format_string_pieces),*);
179 #(#code_fragments);*;
180 ops.push(PrintfTestGeneratorOps::Finalize);
181 (format_string, ops)
182 }
183 })
184 }
string_fragment(&mut self, string: &str) -> Result<()>185 fn string_fragment(&mut self, string: &str) -> Result<()> {
186 self.code_fragments.push(quote! {
187 ops.push(PrintfTestGeneratorOps::StringFragment(#string.to_string()));
188 });
189 Ok(())
190 }
integer_conversion(&mut self, ty: Ident, expression: Arg) -> Result<Option<String>>191 fn integer_conversion(&mut self, ty: Ident, expression: Arg) -> Result<Option<String>> {
192 let ty_str = format!("{ty}");
193 let expression = format!("{}", expression.to_token_stream());
194 self.code_fragments.push(quote! {
195 ops.push(PrintfTestGeneratorOps::IntegerConversion{
196 ty: #ty_str.to_string(),
197 arg: #expression.to_string(),
198 });
199 });
200 Ok(self.integer_specifier_override.clone())
201 }
202
string_conversion(&mut self, expression: Arg) -> Result<Option<String>>203 fn string_conversion(&mut self, expression: Arg) -> Result<Option<String>> {
204 let expression = format!("{}", expression.to_token_stream());
205 self.code_fragments.push(quote! {
206 ops.push(PrintfTestGeneratorOps::StringConversion(#expression.to_string()));
207 });
208 Ok(self.string_specifier_override.clone())
209 }
210
char_conversion(&mut self, expression: Arg) -> Result<Option<String>>211 fn char_conversion(&mut self, expression: Arg) -> Result<Option<String>> {
212 let expression = format!("{}", expression.to_token_stream());
213 self.code_fragments.push(quote! {
214 ops.push(PrintfTestGeneratorOps::CharConversion(#expression.to_string()));
215 });
216 Ok(self.char_specifier_override.clone())
217 }
218
untyped_conversion(&mut self, expression: Arg) -> Result<()>219 fn untyped_conversion(&mut self, expression: Arg) -> Result<()> {
220 let expression = format!("{}", expression.to_token_stream());
221 self.code_fragments.push(quote! {
222 ops.push(PrintfTestGeneratorOps::UntypedConversion(#expression.to_string()));
223 });
224 Ok(())
225 }
226 }
227
printf_generator_test_macro_impl<T: FormatStringParser>(tokens: TokenStream) -> TokenStream228 fn printf_generator_test_macro_impl<T: FormatStringParser>(tokens: TokenStream) -> TokenStream {
229 let format_and_args = parse_macro_input!(tokens as FormatAndArgsFlavor<T>);
230 let generator = PrintfTestGenerator::new();
231 match generate_printf(generator, format_and_args.into()) {
232 Ok(token_stream) => token_stream.into(),
233 Err(e) => e.to_compile_error().into(),
234 }
235 }
236
237 #[proc_macro]
printf_format_printf_generator_test_macro(tokens: TokenStream) -> TokenStream238 pub fn printf_format_printf_generator_test_macro(tokens: TokenStream) -> TokenStream {
239 printf_generator_test_macro_impl::<PrintfFormatStringParser>(tokens)
240 }
241
242 #[proc_macro]
core_fmt_format_printf_generator_test_macro(tokens: TokenStream) -> TokenStream243 pub fn core_fmt_format_printf_generator_test_macro(tokens: TokenStream) -> TokenStream {
244 printf_generator_test_macro_impl::<CoreFmtFormatStringParser>(tokens)
245 }
246
247 // Causes the generator to substitute %d with %K.
248 #[proc_macro]
integer_sub_printf_format_printf_generator_test_macro(tokens: TokenStream) -> TokenStream249 pub fn integer_sub_printf_format_printf_generator_test_macro(tokens: TokenStream) -> TokenStream {
250 let format_and_args =
251 parse_macro_input!(tokens as FormatAndArgsFlavor<PrintfFormatStringParser>);
252 let generator = PrintfTestGenerator::new().with_integer_specifier("%K");
253 match generate_printf(generator, format_and_args.into()) {
254 Ok(token_stream) => token_stream.into(),
255 Err(e) => e.to_compile_error().into(),
256 }
257 }
258
259 // Causes the generator to substitute %s with %K.
260 #[proc_macro]
string_sub_printf_format_printf_generator_test_macro(tokens: TokenStream) -> TokenStream261 pub fn string_sub_printf_format_printf_generator_test_macro(tokens: TokenStream) -> TokenStream {
262 let format_and_args =
263 parse_macro_input!(tokens as FormatAndArgsFlavor<PrintfFormatStringParser>);
264 let generator = PrintfTestGenerator::new().with_string_specifier("%K");
265 match generate_printf(generator, format_and_args.into()) {
266 Ok(token_stream) => token_stream.into(),
267 Err(e) => e.to_compile_error().into(),
268 }
269 }
270
271 // Causes the generator to substitute %c with %K.
272 #[proc_macro]
char_sub_printf_format_printf_generator_test_macro(tokens: TokenStream) -> TokenStream273 pub fn char_sub_printf_format_printf_generator_test_macro(tokens: TokenStream) -> TokenStream {
274 let format_and_args =
275 parse_macro_input!(tokens as FormatAndArgsFlavor<PrintfFormatStringParser>);
276 let generator = PrintfTestGenerator::new().with_char_specifier("%K");
277 match generate_printf(generator, format_and_args.into()) {
278 Ok(token_stream) => token_stream.into(),
279 Err(e) => e.to_compile_error().into(),
280 }
281 }
282
283 // Generator for testing `generate_core_fmt()`. Allows control over the return
284 // value of the conversion functions.
285 struct CoreFmtTestGenerator {
286 code_fragments: Vec<TokenStream2>,
287 integer_specifier_override: Option<String>,
288 string_specifier_override: Option<String>,
289 char_specifier_override: Option<String>,
290 }
291
292 impl CoreFmtTestGenerator {
new() -> Self293 pub fn new() -> Self {
294 Self {
295 code_fragments: Vec::new(),
296 integer_specifier_override: None,
297 string_specifier_override: None,
298 char_specifier_override: None,
299 }
300 }
301
with_integer_specifier(mut self, specifier: &str) -> Self302 pub fn with_integer_specifier(mut self, specifier: &str) -> Self {
303 self.integer_specifier_override = Some(specifier.to_string());
304 self
305 }
306
with_string_specifier(mut self, specifier: &str) -> Self307 pub fn with_string_specifier(mut self, specifier: &str) -> Self {
308 self.string_specifier_override = Some(specifier.to_string());
309 self
310 }
311
with_char_specifier(mut self, specifier: &str) -> Self312 pub fn with_char_specifier(mut self, specifier: &str) -> Self {
313 self.char_specifier_override = Some(specifier.to_string());
314 self
315 }
316 }
317
318 // Until they diverge, we reuse `PrintfTestGeneratorOps` here.
319 impl CoreFmtFormatMacroGenerator for CoreFmtTestGenerator {
finalize(self, format_string: String) -> Result<TokenStream2>320 fn finalize(self, format_string: String) -> Result<TokenStream2> {
321 // Create locally scoped alias so we can refer to them in `quote!()`.
322 let code_fragments = self.code_fragments;
323
324 Ok(quote! {
325 {
326 use pw_format_test_macros_test::PrintfTestGeneratorOps;
327 let mut ops = Vec::new();
328 #(#code_fragments);*;
329 ops.push(PrintfTestGeneratorOps::Finalize);
330 (#format_string, ops)
331 }
332 })
333 }
string_fragment(&mut self, string: &str) -> Result<()>334 fn string_fragment(&mut self, string: &str) -> Result<()> {
335 self.code_fragments.push(quote! {
336 ops.push(PrintfTestGeneratorOps::StringFragment(#string.to_string()));
337 });
338 Ok(())
339 }
integer_conversion(&mut self, ty: Ident, expression: Arg) -> Result<Option<String>>340 fn integer_conversion(&mut self, ty: Ident, expression: Arg) -> Result<Option<String>> {
341 let ty_str = format!("{ty}");
342 let expression = format!("{}", expression.to_token_stream());
343 self.code_fragments.push(quote! {
344 ops.push(PrintfTestGeneratorOps::IntegerConversion{
345 ty: #ty_str.to_string(),
346 arg: #expression.to_string()
347 });
348 });
349 Ok(self.integer_specifier_override.clone())
350 }
351
string_conversion(&mut self, expression: Arg) -> Result<Option<String>>352 fn string_conversion(&mut self, expression: Arg) -> Result<Option<String>> {
353 let expression = format!("{}", expression.to_token_stream());
354 self.code_fragments.push(quote! {
355 ops.push(PrintfTestGeneratorOps::StringConversion(#expression.to_string()));
356 });
357 Ok(self.string_specifier_override.clone())
358 }
359
char_conversion(&mut self, expression: Arg) -> Result<Option<String>>360 fn char_conversion(&mut self, expression: Arg) -> Result<Option<String>> {
361 let expression = format!("{}", expression.to_token_stream());
362 self.code_fragments.push(quote! {
363 ops.push(PrintfTestGeneratorOps::CharConversion(#expression.to_string()));
364 });
365 Ok(self.char_specifier_override.clone())
366 }
367
untyped_conversion(&mut self, expression: Arg) -> Result<()>368 fn untyped_conversion(&mut self, expression: Arg) -> Result<()> {
369 let expression = format!("{}", expression.to_token_stream());
370 self.code_fragments.push(quote! {
371 ops.push(PrintfTestGeneratorOps::UntypedConversion(#expression.to_string()));
372 });
373 Ok(())
374 }
375 }
376
core_fmt_generator_test_macro_impl<T: FormatStringParser>(tokens: TokenStream) -> TokenStream377 fn core_fmt_generator_test_macro_impl<T: FormatStringParser>(tokens: TokenStream) -> TokenStream {
378 let format_and_args = parse_macro_input!(tokens as FormatAndArgsFlavor<T>);
379 let generator = CoreFmtTestGenerator::new();
380 match generate_core_fmt(generator, format_and_args.into()) {
381 Ok(token_stream) => token_stream.into(),
382 Err(e) => e.to_compile_error().into(),
383 }
384 }
385
386 #[proc_macro]
printf_format_core_fmt_generator_test_macro(tokens: TokenStream) -> TokenStream387 pub fn printf_format_core_fmt_generator_test_macro(tokens: TokenStream) -> TokenStream {
388 core_fmt_generator_test_macro_impl::<PrintfFormatStringParser>(tokens)
389 }
390
391 #[proc_macro]
core_fmt_format_core_fmt_generator_test_macro(tokens: TokenStream) -> TokenStream392 pub fn core_fmt_format_core_fmt_generator_test_macro(tokens: TokenStream) -> TokenStream {
393 core_fmt_generator_test_macro_impl::<CoreFmtFormatStringParser>(tokens)
394 }
395
396 // Causes the generator to substitute {} with {:?}.
397 #[proc_macro]
integer_sub_printf_format_core_fmt_generator_test_macro(tokens: TokenStream) -> TokenStream398 pub fn integer_sub_printf_format_core_fmt_generator_test_macro(tokens: TokenStream) -> TokenStream {
399 let format_and_args =
400 parse_macro_input!(tokens as FormatAndArgsFlavor<PrintfFormatStringParser>);
401 let generator = CoreFmtTestGenerator::new().with_integer_specifier("{:?}");
402 match generate_core_fmt(generator, format_and_args.into()) {
403 Ok(token_stream) => token_stream.into(),
404 Err(e) => e.to_compile_error().into(),
405 }
406 }
407
408 // Causes the generator to substitute {} with {:?}.
409 #[proc_macro]
string_sub_printf_format_core_fmt_generator_test_macro(tokens: TokenStream) -> TokenStream410 pub fn string_sub_printf_format_core_fmt_generator_test_macro(tokens: TokenStream) -> TokenStream {
411 let format_and_args =
412 parse_macro_input!(tokens as FormatAndArgsFlavor<PrintfFormatStringParser>);
413 let generator = CoreFmtTestGenerator::new().with_string_specifier("{:?}");
414 match generate_core_fmt(generator, format_and_args.into()) {
415 Ok(token_stream) => token_stream.into(),
416 Err(e) => e.to_compile_error().into(),
417 }
418 }
419
420 // Causes the generator to substitute {} with {:?}.
421 #[proc_macro]
char_sub_printf_format_core_fmt_generator_test_macro(tokens: TokenStream) -> TokenStream422 pub fn char_sub_printf_format_core_fmt_generator_test_macro(tokens: TokenStream) -> TokenStream {
423 let format_and_args =
424 parse_macro_input!(tokens as FormatAndArgsFlavor<PrintfFormatStringParser>);
425 let generator = CoreFmtTestGenerator::new().with_char_specifier("{:?}");
426 match generate_core_fmt(generator, format_and_args.into()) {
427 Ok(token_stream) => token_stream.into(),
428 Err(e) => e.to_compile_error().into(),
429 }
430 }
431