ndless_macros/
lib.rs

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	// check the function signature
14	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}