extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate core;
extern crate proc_macro2;
#[macro_use]
extern crate syn;
mod api_trait;
mod arch;
use proc_macro::TokenStream;
use proc_macro2::Span;
use syn::{FnArg, ItemFn, PathArguments, Type, Visibility, parse, spanned::Spanned};
#[proc_macro_attribute]
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
let f = parse_macro_input!(input as ItemFn);
if f.sig.inputs.len() > 3 {
return parse::Error::new(
f.sig.inputs.last().unwrap().span(),
"`#[entry]` function has too many arguments",
)
.to_compile_error()
.into();
}
for arg in &f.sig.inputs {
match arg {
FnArg::Receiver(_) => {
return parse::Error::new(arg.span(), "invalid argument")
.to_compile_error()
.into();
}
FnArg::Typed(t) => {
if !is_simple_type(&t.ty, "usize") {
return parse::Error::new(t.ty.span(), "argument type must be usize")
.to_compile_error()
.into();
}
}
}
}
let valid_signature = f.sig.constness.is_none()
&& f.sig.asyncness.is_none()
&& f.vis == Visibility::Inherited
&& f.sig.abi.is_none()
&& f.sig.generics.params.is_empty()
&& f.sig.generics.where_clause.is_none()
&& f.sig.variadic.is_none()
;
if !valid_signature {
return parse::Error::new(
f.span(),
"`#[entry]` function must have signature `[unsafe] fn([arg0: usize, ...]) `",
)
.to_compile_error()
.into();
}
if !args.is_empty() {
return parse::Error::new(Span::call_site(), "This attribute accepts no arguments")
.to_compile_error()
.into();
}
let attrs = f.attrs;
let unsafety = f.sig.unsafety;
let args = f.sig.inputs;
let stmts = f.block.stmts;
quote!(
#[allow(non_snake_case)]
#[unsafe(no_mangle)]
#(#attrs)*
pub #unsafety extern "C" fn __sparreal_rt_main(#args) {
#(#stmts)*
}
)
.into()
}
#[allow(unused)]
fn is_simple_type(ty: &Type, name: &str) -> bool {
if let Type::Path(p) = ty {
if p.qself.is_none() && p.path.leading_colon.is_none() && p.path.segments.len() == 1 {
let segment = p.path.segments.first().unwrap();
if segment.ident == name && segment.arguments == PathArguments::None {
return true;
}
}
}
false
}
const NAMESPACE: &str = "sparreal_os";
#[proc_macro_attribute]
pub fn api_trait(_args: TokenStream, item: TokenStream) -> TokenStream {
abi_singleton::api_trait(item, NAMESPACE)
}
#[proc_macro_attribute]
pub fn api_impl(_args: TokenStream, item: TokenStream) -> TokenStream {
abi_singleton::api_impl(item, NAMESPACE)
}
#[proc_macro]
pub fn build_test_setup(_input: TokenStream) -> TokenStream {
quote! {
println!("cargo::rustc-link-arg-tests=-Tlink.x");
println!("cargo::rustc-link-arg-tests=-no-pie");
println!("cargo::rustc-link-arg-tests=-znostart-stop-gc");
}
.into()
}
#[proc_macro]
pub fn module_driver(input: TokenStream) -> TokenStream {
let input = proc_macro2::TokenStream::from(input);
let mut name = None;
{
let mut it = input.clone().into_iter();
while let Some(t) = it.next() {
if let proc_macro2::TokenTree::Ident(i) = t {
if i == "name" {
it.next();
if let Some(proc_macro2::TokenTree::Literal(l)) = it.next() {
let l = l.to_string();
let l = l.trim_matches('"');
name = Some(l.to_string());
break;
}
}
}
}
}
let st_name = name.unwrap_or_default().replace("-", "_").replace(" ", "_");
let static_name = format_ident!("DRIVER_{}", st_name.to_uppercase());
quote! {
#[unsafe(link_section = ".driver.register")]
#[unsafe(no_mangle)]
#[used(linker)]
pub static #static_name: sparreal_kernel::driver_interface::DriverRegister = sparreal_kernel::driver_interface::DriverRegister{
#input
};
}
.into()
}