blob: 27077ffcfec365bc4b7a55c311b5e65540c68a4c (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
//! The `#[routeify]` extension — transforms `expr?` into `route!(expr)`.
//!
//! Designed as an extension for the Mingling attribute macro system, intended
//! to be used with `#[chain(routeify)]` or standalone as `#[routeify]`.
//!
//! # How it works
//!
//! The macro parses the function AST and replaces every `Expr::Try` node with an
//! equivalent `route!(expr)` invocation.
use proc_macro::TokenStream;
use quote::ToTokens;
use syn::spanned::Spanned;
use syn::visit_mut::VisitMut;
use syn::{parse_macro_input, Expr, ItemFn};
struct RouteifyTransform;
impl VisitMut for RouteifyTransform {
fn visit_expr_mut(&mut self, expr: &mut Expr) {
syn::visit_mut::visit_expr_mut(self, expr);
if let Expr::Try(try_expr) = expr {
let inner = &*try_expr.expr;
let inner_tokens = inner.to_token_stream();
// Set the span of the generated `route` ident to the `?` token's span,
// so that rust-analyzer resolves the `?` position to the `route!` macro
// instead of the standard Try trait, showing the route macro's docs on hover.
let q_span = try_expr.question_token.span();
let route_ident = proc_macro2::Ident::new("route", q_span);
if let Ok(macro_expr) = syn::parse2::<Expr>(quote::quote! {
::mingling::macros::#route_ident!(#inner_tokens)
}) {
*expr = macro_expr;
}
}
}
}
pub(crate) fn routeify_impl(_attr: TokenStream, item: TokenStream) -> TokenStream {
let mut input_fn = parse_macro_input!(item as ItemFn);
RouteifyTransform.visit_item_fn_mut(&mut input_fn);
input_fn.to_token_stream().into()
}
|