const_format_proc_macros/
format_args.rs

1use crate::{
2    format_str::FormatStr, formatting::FormattingFlags, parse_utils::StrRawness,
3    parse_utils::TokenStream2Ext, shared_arg_parsing::ExprArg, spanned::Spans,
4};
5
6use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
7
8use quote::{quote_spanned, TokenStreamExt};
9
10////////////////////////////////////////////////
11
12mod parsing;
13
14////////////////////////////////////////////////
15
16struct UncheckedFormatArgs {
17    literal: FormatStr,
18    args: Vec<UncheckedFormatArg>,
19}
20
21struct UncheckedFormatArg {
22    pub(crate) spans: Spans,
23    pub(crate) ident: Option<Ident>,
24    // The identifier for the Formatter passed to format the argument.
25    // If this is Some, then `expr` is expanded directly,
26    pub(crate) fmt_ident: Option<Ident>,
27    /// Using a TokenStream2 because it is validated to be a valid expression in
28    /// the macro_rules! macros that call these proc macros.
29    pub(crate) expr: TokenStream2,
30}
31
32pub(crate) struct FormatArgs {
33    pub(crate) condition: Option<ExprArg>,
34    pub(crate) local_variables: Vec<LocalVariable>,
35    pub(crate) expanded_into: Vec<ExpandInto>,
36}
37
38pub(crate) struct FormatIfArgs {
39    pub(crate) inner: FormatArgs,
40}
41
42/// The arguments of `writec`
43pub(crate) struct WriteArgs {
44    pub(crate) writer_expr: TokenStream2,
45    pub(crate) writer_span: Span,
46    pub(crate) format_args: FormatArgs,
47}
48
49pub(crate) enum ExpandInto {
50    Str(String, StrRawness),
51    Formatted(ExpandFormatted),
52    WithFormatter(ExpandWithFormatter),
53}
54
55pub(crate) struct ExpandFormatted {
56    pub(crate) format: FormattingFlags,
57    pub(crate) local_variable: Ident,
58}
59
60pub(crate) struct ExpandWithFormatter {
61    pub(crate) format: FormattingFlags,
62    pub(crate) fmt_ident: Ident,
63    pub(crate) expr: TokenStream2,
64}
65
66pub(crate) struct LocalVariable {
67    // The local variable that the macro will output for this argument,
68    // so that it is not evaluated multiple times when it's used multiple times
69    // in the format string.
70    pub(crate) ident: Ident,
71    /// Using a TokenStream2 because it is validated to be a valid expression in
72    /// the macro_rules! macros that call these proc macros.
73    pub(crate) expr: TokenStream2,
74}
75
76pub(crate) enum FormatArg {
77    WithFormatter {
78        // The identifier for the Formatter passed to format the argument.
79        // If this is Some, then `expr` is expanded directly,
80        fmt_ident: Ident,
81        /// Using a TokenStream2 because it is validated to be a valid expression in
82        /// the macro_rules! macros that call these proc macros.
83        expr: TokenStream2,
84    },
85    WithLocal(Ident),
86}
87
88////////////////////////////////////////////////
89
90impl ExpandInto {
91    pub(crate) fn fmt_call(&self, formatter: &Ident) -> TokenStream2 {
92        match self {
93            ExpandInto::Str(str, rawness) => {
94                let str_tokens = rawness.tokenize_sub(str);
95
96                quote_spanned!(rawness.span()=> #formatter.write_str(#str_tokens) )
97            }
98            ExpandInto::Formatted(fmted) => {
99                let flags = fmted.format;
100                let fmt_method = fmted.format.fmt_method_name();
101                let local_variable = &fmted.local_variable;
102                let span = local_variable.span();
103
104                let mut tokens = quote::quote!(
105                    __cf_osRcTFl4A::coerce_to_fmt!(&#local_variable)
106                        .#fmt_method
107                )
108                .set_span_recursive(span);
109
110                tokens.append_all(quote::quote!( (&mut #formatter.make_formatter(#flags)) ));
111
112                tokens
113            }
114            ExpandInto::WithFormatter(ExpandWithFormatter {
115                format,
116                fmt_ident,
117                expr,
118            }) => quote::quote!({
119                let #fmt_ident = &mut #formatter.make_formatter(#format);
120                __cf_osRcTFl4A::pmr::ToResult( #expr ).to_result()
121            }),
122        }
123    }
124}