1 | use crate::{ |
2 | format_str::FormatStr, formatting::FormattingFlags, parse_utils::StrRawness, |
3 | parse_utils::TokenStream2Ext, shared_arg_parsing::ExprArg, spanned::Spans, |
4 | }; |
5 | |
6 | use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; |
7 | |
8 | use quote::{quote_spanned, TokenStreamExt}; |
9 | |
10 | //////////////////////////////////////////////// |
11 | |
12 | mod parsing; |
13 | |
14 | //////////////////////////////////////////////// |
15 | |
16 | struct UncheckedFormatArgs { |
17 | literal: FormatStr, |
18 | args: Vec<UncheckedFormatArg>, |
19 | } |
20 | |
21 | struct 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 | |
32 | pub(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 | |
38 | pub(crate) struct FormatIfArgs { |
39 | pub(crate) inner: FormatArgs, |
40 | } |
41 | |
42 | /// The arguments of `writec` |
43 | pub(crate) struct WriteArgs { |
44 | pub(crate) writer_expr: TokenStream2, |
45 | pub(crate) writer_span: Span, |
46 | pub(crate) format_args: FormatArgs, |
47 | } |
48 | |
49 | pub(crate) enum ExpandInto { |
50 | Str(String, StrRawness), |
51 | Formatted(ExpandFormatted), |
52 | WithFormatter(ExpandWithFormatter), |
53 | } |
54 | |
55 | pub(crate) struct ExpandFormatted { |
56 | pub(crate) format: FormattingFlags, |
57 | pub(crate) local_variable: Ident, |
58 | } |
59 | |
60 | pub(crate) struct ExpandWithFormatter { |
61 | pub(crate) format: FormattingFlags, |
62 | pub(crate) fmt_ident: Ident, |
63 | pub(crate) expr: TokenStream2, |
64 | } |
65 | |
66 | pub(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 | |
76 | pub(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 | |
90 | impl 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 | } |
125 | |