1use defmt_parser::ParserMode;
2use proc_macro::TokenStream;
3use proc_macro_error2::abort;
4use quote::quote;
5use syn::{parse_macro_input, parse_quote};
6
7use crate::{construct, function_like::log};
8
9use self::args::Args;
10
11mod args;
12
13pub(crate) fn expand(args: TokenStream) -> TokenStream {
14 let Args {
15 formatter,
16 log_args,
17 ..
18 } = parse_macro_input!(args as Args);
19
20 let format_string = log_args.format_string.value();
21 let fragments = match defmt_parser::parse(&format_string, ParserMode::Strict) {
22 Ok(args) => args,
23 Err(e) => abort!(log_args.format_string, "{}", e),
24 };
25
26 let formatting_exprs: Vec<_> = log_args
27 .formatting_args
28 .map(|punctuated| punctuated.into_iter().collect())
29 .unwrap_or_default();
30
31 let log::Codegen { patterns, exprs } = log::Codegen::new(
32 &fragments,
33 formatting_exprs.len(),
34 log_args.format_string.span(),
35 );
36
37 let format_tag =
38 construct::interned_string(&format_string, "write", false, None, &parse_quote!(defmt));
39 quote!({
40 let _typecheck_formatter: defmt::Formatter<'_> = #formatter;
41 match (#(&(#formatting_exprs)),*) {
42 (#(#patterns),*) => {
43 defmt::export::istr(&#format_tag);
44 #(#exprs;)*
45 }
46 }
47 })
48 .into()
49}
50