1use proc_macro::TokenStream;
2use syn::parse::Parser;
3use syn::spanned::Spanned;
4use syn::visit_mut::VisitMut;
5use syn::{Expr, Ident, Token};
6
7struct InferVisit;
8struct RefOpsVisit;
9struct IndexVisit;
10
11fn visit_expr_macro<V: VisitMut>(v: &mut V, i: &mut syn::ExprMacro) {
12 if let Ok(mut mac) = syn::punctuated::Punctuated::<Expr, Token![,]>::parse_terminated
13 .parse2(i.mac.tokens.clone())
14 {
15 for e in &mut mac {
16 v.visit_expr_mut(e);
17 }
18 i.mac.tokens = quote::quote!(#mac);
19 return;
20 }
21
22 if let Ok(mut mac) = syn::punctuated::Punctuated::<Expr, Token![;]>::parse_terminated
23 .parse2(i.mac.tokens.clone())
24 {
25 for e in &mut mac {
26 v.visit_expr_mut(e);
27 }
28 i.mac.tokens = quote::quote!(#mac);
29 return;
30 }
31}
32
33impl VisitMut for InferVisit {
34 fn visit_expr_macro_mut(&mut self, i: &mut syn::ExprMacro) {
35 visit_expr_macro(self, i)
36 }
37
38 fn visit_angle_bracketed_generic_arguments_mut(
39 &mut self,
40 _: &mut syn::AngleBracketedGenericArguments,
41 ) {
42 }
43
44 fn visit_generic_argument_mut(&mut self, _: &mut syn::GenericArgument) {}
45
46 fn visit_generic_param_mut(&mut self, _: &mut syn::GenericParam) {}
47
48 fn visit_generics_mut(&mut self, _: &mut syn::Generics) {}
49
50 fn visit_parenthesized_generic_arguments_mut(
51 &mut self,
52 _: &mut syn::ParenthesizedGenericArguments,
53 ) {
54 }
55
56 fn visit_expr_mut(&mut self, i: &mut syn::Expr) {
57 match i {
58 Expr::Infer(syn::ExprInfer {
59 attrs,
60 underscore_token,
61 }) => {
62 let krate = syn::Stmt::Item(syn::Item::ExternCrate(syn::ItemExternCrate {
63 attrs: vec![],
64 vis: syn::Visibility::Inherited,
65 extern_token: Default::default(),
66 crate_token: Default::default(),
67 ident: Ident::new("azucar", proc_macro::Span::call_site().into()),
68 rename: None,
69 semi_token: Default::default(),
70 }));
71
72 let call = Expr::Call(syn::ExprCall {
73 attrs: core::mem::take(attrs),
74 func: Box::new(Expr::Path(syn::ExprPath {
75 attrs: vec![],
76 qself: None,
77 path: syn::Path {
78 leading_colon: Some(Default::default()),
79 segments: [
80 syn::PathSegment {
81 ident: Ident::new("azucar", underscore_token.span),
82 arguments: syn::PathArguments::None,
83 },
84 syn::PathSegment {
85 ident: Ident::new("Infer", underscore_token.span),
86 arguments: syn::PathArguments::None,
87 },
88 syn::PathSegment {
89 ident: Ident::new("infer", underscore_token.span),
90 arguments: syn::PathArguments::None,
91 },
92 ]
93 .into_iter()
94 .collect(),
95 },
96 })),
97 paren_token: Default::default(),
98 args: syn::punctuated::Punctuated::new(),
99 });
100
101 *i = Expr::Block(syn::ExprBlock {
102 attrs: vec![],
103 label: None,
104 block: syn::Block {
105 brace_token: Default::default(),
106 stmts: vec![krate, syn::Stmt::Expr(call, None)],
107 },
108 })
109 },
110 _ => {
111 syn::visit_mut::visit_expr_mut(self, i);
112 },
113 }
114 }
115}
116impl VisitMut for RefOpsVisit {
117 fn visit_expr_macro_mut(&mut self, i: &mut syn::ExprMacro) {
118 visit_expr_macro(self, i)
119 }
120
121 fn visit_expr_unary_mut(&mut self, i: &mut syn::ExprUnary) {
122 syn::visit_mut::visit_expr_unary_mut(self, i);
123
124 match i.op {
125 syn::UnOp::Not(_) | syn::UnOp::Neg(_) => {
126 *i.expr = Expr::Reference(syn::ExprReference {
127 attrs: vec![],
128 and_token: Default::default(),
129 mutability: None,
130 expr: Box::new(core::mem::replace(&mut i.expr, Expr::PLACEHOLDER)),
131 });
132 },
133 _ => {},
134 };
135 }
136
137 fn visit_expr_binary_mut(&mut self, i: &mut syn::ExprBinary) {
138 syn::visit_mut::visit_expr_binary_mut(self, i);
139
140 match i.op {
141 syn::BinOp::Add(_)
142 | syn::BinOp::Sub(_)
143 | syn::BinOp::Mul(_)
144 | syn::BinOp::Div(_)
145 | syn::BinOp::Rem(_)
146 | syn::BinOp::And(_)
147 | syn::BinOp::Or(_)
148 | syn::BinOp::BitXor(_)
149 | syn::BinOp::BitAnd(_)
150 | syn::BinOp::BitOr(_)
151 | syn::BinOp::Shl(_)
152 | syn::BinOp::Shr(_) => {
153 for e in [&mut i.left, &mut i.right] {
154 **e = Expr::Reference(syn::ExprReference {
155 attrs: vec![],
156 and_token: Default::default(),
157 mutability: None,
158 expr: Box::new(core::mem::replace(e, Expr::PLACEHOLDER)),
159 });
160 }
161 },
162 _ => {},
163 }
164 }
165}
166
167impl VisitMut for IndexVisit {
168 fn visit_expr_macro_mut(&mut self, i: &mut syn::ExprMacro) {
169 visit_expr_macro(self, i);
170 }
171
172 fn visit_expr_mut(&mut self, i: &mut syn::Expr) {
173 syn::visit_mut::visit_expr_mut(self, i);
174
175 match i {
176 Expr::Index(e) => match &mut *e.index {
177 Expr::Unary(syn::ExprUnary { attrs, op, expr }) => match op {
178 syn::UnOp::Deref(_) => {
179 let index = core::mem::replace(&mut **expr, Expr::PLACEHOLDER);
180 let expr = core::mem::replace(&mut *e.expr, Expr::PLACEHOLDER);
181
182 let krate = syn::Stmt::Item(syn::Item::ExternCrate(syn::ItemExternCrate {
183 attrs: vec![],
184 vis: syn::Visibility::Inherited,
185 extern_token: Default::default(),
186 crate_token: Default::default(),
187 ident: Ident::new("azucar", proc_macro::Span::call_site().into()),
188 rename: None,
189 semi_token: Default::default(),
190 }));
191
192 let call = Expr::Call(syn::ExprCall {
193 attrs: core::mem::take(attrs),
194 func: Box::new(Expr::Path(syn::ExprPath {
195 attrs: vec![],
196 qself: None,
197 path: syn::Path {
198 leading_colon: Some(Default::default()),
199 segments: [
200 syn::PathSegment {
201 ident: Ident::new(
202 "azucar",
203 e.bracket_token.span.span(),
204 ),
205 arguments: syn::PathArguments::None,
206 },
207 syn::PathSegment {
208 ident: Ident::new(
209 "IndexMove",
210 e.bracket_token.span.span(),
211 ),
212 arguments: syn::PathArguments::None,
213 },
214 syn::PathSegment {
215 ident: Ident::new(
216 "index_move",
217 e.bracket_token.span.span(),
218 ),
219 arguments: syn::PathArguments::None,
220 },
221 ]
222 .into_iter()
223 .collect(),
224 },
225 })),
226 paren_token: Default::default(),
227 args: [expr, index].into_iter().collect(),
228 });
229
230 *i = Expr::Block(syn::ExprBlock {
231 attrs: vec![],
232 label: None,
233 block: syn::Block {
234 brace_token: Default::default(),
235 stmts: vec![krate, syn::Stmt::Expr(call, None)],
236 },
237 })
238 },
239 _ => {},
240 },
241 Expr::Reference(syn::ExprReference {
242 attrs,
243 and_token,
244 mutability,
245 expr,
246 }) => {
247 let index = core::mem::replace(&mut **expr, Expr::PLACEHOLDER);
248
249 let expr = Box::new(core::mem::replace(&mut *e.expr, Expr::PLACEHOLDER));
250 let is_mut = mutability.is_some();
251
252 let expr = Expr::Reference(syn::ExprReference {
253 attrs: core::mem::take(attrs),
254 and_token: *and_token,
255 mutability: *mutability,
256 expr,
257 });
258
259 let krate = syn::Stmt::Item(syn::Item::ExternCrate(syn::ItemExternCrate {
260 attrs: vec![],
261 vis: syn::Visibility::Inherited,
262 extern_token: Default::default(),
263 crate_token: Default::default(),
264 ident: Ident::new("azucar", proc_macro::Span::call_site().into()),
265 rename: None,
266 semi_token: Default::default(),
267 }));
268
269 let call = Expr::Call(syn::ExprCall {
270 attrs: core::mem::take(attrs),
271 func: Box::new(Expr::Path(syn::ExprPath {
272 attrs: vec![],
273 qself: None,
274 path: syn::Path {
275 leading_colon: Some(Default::default()),
276 segments: [
277 syn::PathSegment {
278 ident: Ident::new("azucar", e.bracket_token.span.span()),
279 arguments: syn::PathArguments::None,
280 },
281 syn::PathSegment {
282 ident: Ident::new(
283 if is_mut { "IndexMut" } else { "Index" },
284 e.bracket_token.span.span(),
285 ),
286 arguments: syn::PathArguments::None,
287 },
288 syn::PathSegment {
289 ident: Ident::new(
290 if is_mut { "index_mut" } else { "index" },
291 e.bracket_token.span.span(),
292 ),
293 arguments: syn::PathArguments::None,
294 },
295 ]
296 .into_iter()
297 .collect(),
298 },
299 })),
300 paren_token: Default::default(),
301 args: [expr, index].into_iter().collect(),
302 });
303
304 *i = Expr::Block(syn::ExprBlock {
305 attrs: vec![],
306 label: None,
307 block: syn::Block {
308 brace_token: Default::default(),
309 stmts: vec![krate, syn::Stmt::Expr(call, None)],
310 },
311 })
312 },
313 _ => {},
314 },
315 _ => {},
316 }
317 }
318}
319
320#[proc_macro_attribute]
321pub fn ref_ops(_: TokenStream, item: TokenStream) -> TokenStream {
322 let mut item = syn::parse_macro_input!(item as syn::Item);
323
324 RefOpsVisit.visit_item_mut(&mut item);
325
326 quote::quote!(#item).into()
327}
328
329#[proc_macro_attribute]
330pub fn infer(_: TokenStream, item: TokenStream) -> TokenStream {
331 let mut item = syn::parse_macro_input!(item as syn::Item);
332
333 InferVisit.visit_item_mut(&mut item);
334
335 quote::quote!(#item).into()
336}
337
338#[proc_macro_attribute]
339pub fn index(_: TokenStream, item: TokenStream) -> TokenStream {
340 let mut item = syn::parse_macro_input!(item as syn::Item);
341
342 IndexVisit.visit_item_mut(&mut item);
343
344 quote::quote!(#item).into()
345}