expression_formatter/
lib.rs1use proc_macro::TokenStream;
2use syn::{Expr, LitStr};
3
4#[proc_macro]
5pub fn format(tokens: TokenStream) -> TokenStream {
6 let string = syn::parse_macro_input!(tokens as LitStr).value();
7
8 let mut format_string = String::new();
9 let mut expressions: Vec<Expr> = Vec::new();
10 let mut start_index = 0;
11
12 while start_index < string.len() {
13 if string.chars().nth(start_index).unwrap() == '}' {
15 panic!("Unexpected closing brace");
16 }
17
18 if string.chars().nth(start_index).unwrap() != '{' {
20 format_string += &string.chars().nth(start_index).unwrap().to_string();
21 start_index += 1;
22 continue;
23 }
24
25 start_index += 1;
27
28 let (expression, length) = parse_expr(&string, start_index, string.len() - 1);
30 start_index += length;
31
32 while string.chars().nth(start_index).unwrap() != '}' {
33 start_index += 1;
34 }
35
36 if string.chars().nth(start_index).unwrap() != '}' {
38 panic!("Missing closing brace after expression");
39 }
40 start_index += 1;
41
42 format_string += "{}";
44 expressions.push(expression);
45 }
46
47 quote::quote! {
48 std::format!(#format_string, #(#expressions),*)
49 }
50 .into()
51}
52
53#[proc_macro]
54pub fn println(tokens: TokenStream) -> TokenStream {
55 let string = syn::parse_macro_input!(tokens as LitStr).value();
56
57 let mut format_string = String::new();
58 let mut expressions: Vec<Expr> = Vec::new();
59 let mut start_index = 0;
60
61 while start_index < string.len() {
62 if string.chars().nth(start_index).unwrap() == '}' {
64 panic!("Unexpected closing brace");
65 }
66
67 if string.chars().nth(start_index).unwrap() != '{' {
69 format_string += &string.chars().nth(start_index).unwrap().to_string();
70 start_index += 1;
71 continue;
72 }
73
74 start_index += 1;
76
77 let (expression, length) = parse_expr(&string, start_index, string.len() - 1);
79 start_index += length;
80
81 while string.chars().nth(start_index).unwrap() != '}' {
82 start_index += 1;
83 }
84
85 if string.chars().nth(start_index).unwrap() != '}' {
87 panic!("Missing closing brace after expression");
88 }
89 start_index += 1;
90
91 format_string += "{}";
93 expressions.push(expression);
94 }
95
96 quote::quote! {
97 std::println!(#format_string, #(#expressions),*)
98 }
99 .into()
100}
101
102#[proc_macro]
103pub fn print(tokens: TokenStream) -> TokenStream {
104 let string = syn::parse_macro_input!(tokens as LitStr).value();
105
106 let mut format_string = String::new();
107 let mut expressions: Vec<Expr> = Vec::new();
108 let mut start_index = 0;
109
110 while start_index < string.len() {
111 if string.chars().nth(start_index).unwrap() == '}' {
113 panic!("Unexpected closing brace");
114 }
115
116 if string.chars().nth(start_index).unwrap() != '{' {
118 format_string += &string.chars().nth(start_index).unwrap().to_string();
119 start_index += 1;
120 continue;
121 }
122
123 start_index += 1;
125
126 let (expression, length) = parse_expr(&string, start_index, string.len() - 1);
128 start_index += length;
129
130 while string.chars().nth(start_index).unwrap() != '}' {
131 start_index += 1;
132 }
133
134 if string.chars().nth(start_index).unwrap() != '}' {
136 panic!("Missing closing brace after expression");
137 }
138 start_index += 1;
139
140 format_string += "{}";
142 expressions.push(expression);
143 }
144
145 quote::quote! {
146 std::print!(#format_string, #(#expressions),*)
147 }
148 .into()
149}
150
151#[proc_macro]
152pub fn eprint(tokens: TokenStream) -> TokenStream {
153 let string = syn::parse_macro_input!(tokens as LitStr).value();
154
155 let mut format_string = String::new();
156 let mut expressions: Vec<Expr> = Vec::new();
157 let mut start_index = 0;
158
159 while start_index < string.len() {
160 if string.chars().nth(start_index).unwrap() == '}' {
162 panic!("Unexpected closing brace");
163 }
164
165 if string.chars().nth(start_index).unwrap() != '{' {
167 format_string += &string.chars().nth(start_index).unwrap().to_string();
168 start_index += 1;
169 continue;
170 }
171
172 start_index += 1;
174
175 let (expression, length) = parse_expr(&string, start_index, string.len() - 1);
177 start_index += length;
178
179 while string.chars().nth(start_index).unwrap() != '}' {
180 start_index += 1;
181 }
182
183 if string.chars().nth(start_index).unwrap() != '}' {
185 panic!("Missing closing brace after expression");
186 }
187 start_index += 1;
188
189 format_string += "{}";
191 expressions.push(expression);
192 }
193
194 quote::quote! {
195 std::eprint!(#format_string, #(#expressions),*)
196 }
197 .into()
198}
199
200#[proc_macro]
201pub fn eprintln(tokens: TokenStream) -> TokenStream {
202 let string = syn::parse_macro_input!(tokens as LitStr).value();
203
204 let mut format_string = String::new();
205 let mut expressions: Vec<Expr> = Vec::new();
206 let mut start_index = 0;
207
208 while start_index < string.len() {
209 if string.chars().nth(start_index).unwrap() == '}' {
211 panic!("Unexpected closing brace");
212 }
213
214 if string.chars().nth(start_index).unwrap() != '{' {
216 format_string += &string.chars().nth(start_index).unwrap().to_string();
217 start_index += 1;
218 continue;
219 }
220
221 start_index += 1;
223
224 let (expression, length) = parse_expr(&string, start_index, string.len() - 1);
226 start_index += length;
227
228 while string.chars().nth(start_index).unwrap() != '}' {
229 start_index += 1;
230 }
231
232 if string.chars().nth(start_index).unwrap() != '}' {
234 panic!("Missing closing brace after expression");
235 }
236 start_index += 1;
237
238 format_string += "{}";
240 expressions.push(expression);
241 }
242
243 quote::quote! {
244 std::eprintln!(#format_string, #(#expressions),*)
245 }
246 .into()
247}
248
249fn parse_expr(string: &str, start_index: usize, end_index: usize) -> (Expr, usize) {
250 if end_index <= start_index {
251 panic!("Failed to parse expression");
252 }
253
254 let slice = string.get(start_index .. end_index).unwrap();
255 let expression_attempt: Result<Expr, _> = syn::parse_str(slice);
256 if let Ok(expression) = expression_attempt {
257 (expression, end_index - start_index)
258 } else {
259 parse_expr(string, start_index, end_index - 1)
260 }
261}