1#![feature(box_patterns)]
2use proc_macro::TokenStream;
3use proc_macro2::Span;
4use quote::quote;
5use syn::{parse_macro_input, FnArg, Ident, ItemFn, PatType, ReturnType, Type, TypePath};
6
7#[proc_macro_attribute]
13pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream {
14 #[cfg(feature = "alloc")]
15 let tlsf_init = quote! {
16 unsafe {
18 solo5_rs::ALLOCATOR.lock().init(start.heap_start as *mut u8, start.heap_size as usize);
19 }
20 };
21
22 #[cfg(not(feature = "alloc"))]
23 let tlsf_init = quote! {};
24
25 let body = item.clone();
26 let body = parse_macro_input!(body as ItemFn);
27 let ident = body.sig.ident.clone();
28 let inputs = body.sig.inputs.clone();
29 let solo5_main_arg = match inputs.len() {
30 0 => {
31 quote! {}
32 }
33 1 => {
34 let arg = inputs.first().unwrap();
35 match arg {
36 FnArg::Typed(PatType {
37 attrs: _,
38 pat: _,
39 colon_token: _,
40 ty: box Type::Path(TypePath { qself: _, path }),
41 }) => {
42 if *path.get_ident().unwrap() == Ident::new("Solo5StartInfo", Span::call_site())
43 {
44 quote! {
45 solo5_rs::Solo5StartInfo::from(start)
46 }
47 } else {
48 let entry = quote! {
49 compile_error!("The only argument of solo5_rs::main function must be of type Solo5StartInfo.");
50 #body
51 };
52
53 return TokenStream::from(entry);
54 }
55 }
56 _ => {
57 let entry = quote! {
58 compile_error!("solo5_rs::main function does not take `self`.");
59 #body
60 };
61
62 return TokenStream::from(entry);
63 }
64 }
65 }
66 _ => {
67 let entry = quote! {
68 compile_error!("solo5_rs::main function has too many arguments.");
69 #body
70 };
71
72 return TokenStream::from(entry);
73 }
74 };
75
76 let call_main = match body.sig.output.clone() {
77 ReturnType::Default => quote! {
78 #ident(#solo5_main_arg);
79 return 0;
80 },
81 ReturnType::Type(_, _) => quote! {
82 u64::from(#ident(#solo5_main_arg))
83 },
84 };
85
86 let entry = quote! {
87 #[no_mangle]
88 pub extern "C" fn solo5_app_main(start: &solo5_sys::solo5_start_info) -> u64 {
89 #tlsf_init
90 #call_main
91 }
92 };
93
94 let mut entry = TokenStream::from(entry);
95 entry.extend(item);
96
97 entry
98}