1use proc_macro2::Span;
4use quote::quote;
5use syn::{
6 parse, parse_macro_input, spanned::Spanned, FnArg, ItemFn, ReturnType, Type, Visibility,
7};
8
9use proc_macro::TokenStream;
10
11#[proc_macro_attribute]
13pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
14 let f = parse_macro_input!(input as ItemFn);
15
16 if f.sig.inputs.len() > 1 {
18 return parse::Error::new(
19 f.sig.inputs.last().unwrap().span(),
20 "`#[entry]` function should include at most one parameter",
21 )
22 .to_compile_error()
23 .into();
24 }
25
26 for arg in &f.sig.inputs {
27 match arg {
28 FnArg::Receiver(_) => {
29 return parse::Error::new(arg.span(), "invalid argument")
30 .to_compile_error()
31 .into();
32 }
33 FnArg::Typed(t) => {
34 if let Type::Path(_p) = &*t.ty {
35 } else {
37 return parse::Error::new(t.ty.span(), "argument type must be a path")
38 .to_compile_error()
39 .into();
40 }
41 }
42 }
43 }
44
45 let valid_signature = f.sig.constness.is_none()
47 && f.sig.asyncness.is_none()
48 && f.vis == Visibility::Inherited
49 && f.sig.abi.is_none()
50 && f.sig.generics.params.is_empty()
51 && f.sig.generics.where_clause.is_none()
52 && f.sig.variadic.is_none()
53 && match f.sig.output {
54 ReturnType::Default => true,
55 ReturnType::Type(_, ref ty) => {
56 if let Type::Path(_path) = &**ty {
57 true
58 } else {
59 false
60 }
61 }
62 };
63
64 if !valid_signature {
65 return parse::Error::new(
66 f.span(),
67 "`#[entry]` function must have signature `[unsafe] fn([params: Parameters]) [-> Handover]`",
68 )
69 .to_compile_error()
70 .into();
71 }
72
73 if !args.is_empty() {
74 return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
75 .to_compile_error()
76 .into();
77 }
78
79 let attrs = f.attrs;
80 let unsafety = f.sig.unsafety;
81 let args = f.sig.inputs;
82 let stmts = f.block.stmts;
83 let ret = f.sig.output;
84
85 quote!(
86 #[allow(non_snake_case)]
87 #[export_name = "main"]
88 #(#attrs)*
89 pub #unsafety fn __rom_rt__main(#args) #ret {
90 #(#stmts)*
91 }
92 )
93 .into()
94}