expression_formatter/
lib.rs

1use 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        // Bad opening brace
14        if string.chars().nth(start_index).unwrap() == '}' {
15            panic!("Unexpected closing brace");
16        }
17
18        // Normal character
19        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        // Opening brace
26        start_index += 1;
27
28        // Expression
29        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        // Closing brace
37        if string.chars().nth(start_index).unwrap() != '}' {
38            panic!("Missing closing brace after expression");
39        }
40        start_index += 1;
41
42        // Add expression
43        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        // Bad opening brace
63        if string.chars().nth(start_index).unwrap() == '}' {
64            panic!("Unexpected closing brace");
65        }
66
67        // Normal character
68        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        // Opening brace
75        start_index += 1;
76
77        // Expression
78        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        // Closing brace
86        if string.chars().nth(start_index).unwrap() != '}' {
87            panic!("Missing closing brace after expression");
88        }
89        start_index += 1;
90
91        // Add expression
92        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        // Bad opening brace
112        if string.chars().nth(start_index).unwrap() == '}' {
113            panic!("Unexpected closing brace");
114        }
115
116        // Normal character
117        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        // Opening brace
124        start_index += 1;
125
126        // Expression
127        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        // Closing brace
135        if string.chars().nth(start_index).unwrap() != '}' {
136            panic!("Missing closing brace after expression");
137        }
138        start_index += 1;
139
140        // Add expression
141        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        // Bad opening brace
161        if string.chars().nth(start_index).unwrap() == '}' {
162            panic!("Unexpected closing brace");
163        }
164
165        // Normal character
166        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        // Opening brace
173        start_index += 1;
174
175        // Expression
176        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        // Closing brace
184        if string.chars().nth(start_index).unwrap() != '}' {
185            panic!("Missing closing brace after expression");
186        }
187        start_index += 1;
188
189        // Add expression
190        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        // Bad opening brace
210        if string.chars().nth(start_index).unwrap() == '}' {
211            panic!("Unexpected closing brace");
212        }
213
214        // Normal character
215        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        // Opening brace
222        start_index += 1;
223
224        // Expression
225        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        // Closing brace
233        if string.chars().nth(start_index).unwrap() != '}' {
234            panic!("Missing closing brace after expression");
235        }
236        start_index += 1;
237
238        // Add expression
239        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}