1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4
5use proc_macro2::Span;
6use quote::quote;
7use syn::parse_macro_input;
8use syn::{parse, spanned::Spanned, ItemFn};
9
10#[proc_macro_attribute]
11pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
12 let f = parse_macro_input!(input as ItemFn);
13 let valid_signature = f.sig.constness.is_none()
15 && f.sig.abi.is_none()
16 && f.sig.inputs.is_empty()
17 && f.sig.generics.params.is_empty()
18 && f.sig.generics.where_clause.is_none()
19 && f.sig.variadic.is_none();
20
21 if !valid_signature {
22 return parse::Error::new(
23 f.span(),
24 "`#[entry]` function does not meet specifications!",
25 )
26 .to_compile_error()
27 .into();
28 }
29
30 if !args.is_empty() {
31 return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
32 .to_compile_error()
33 .into();
34 }
35
36 let attrs = f.attrs;
37 let stmts = f.block.stmts;
38 let ret = f.sig.output;
39 let name = f.sig.ident;
40 let unsafety = f.sig.unsafety;
41 let vis = f.vis;
42
43 quote!(
44 #[export_name = "main"]
45 unsafe fn __ndless_start(argc: ::ndless::cty::c_int, argv: *const *const ::ndless::cty::c_char) -> ::ndless::cty::c_int {
46 let args: &[*const ::ndless::cty::c_char] = unsafe { ::core::slice::from_raw_parts(argv, argc as usize) };
47 ::ndless::__init(args);
48 ::ndless::process::Termination::report(#name())
49 }
50
51 #(#attrs)*
52 #vis #unsafety fn #name() #ret {
53 #(#stmts)*
54 }
55 )
56 .into()
57}