Pass a Gba struct argument to the agb entry

This commit is contained in:
Gwilym Kuiper 2022-01-16 21:38:04 +00:00
parent 40b87e6c6f
commit 0d623fc5b0

View file

@ -2,9 +2,9 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro2::Span; use proc_macro2::Span;
use quote::quote; use quote::{quote, ToTokens};
use rand::Rng; use rand::Rng;
use syn::{Ident, ItemFn, ReturnType, Type, Visibility}; use syn::{FnArg, Ident, ItemFn, Pat, ReturnType, Token, Type, Visibility};
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
@ -15,16 +15,43 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
f.sig.constness.is_none() f.sig.constness.is_none()
&& f.vis == Visibility::Inherited && f.vis == Visibility::Inherited
&& f.sig.abi.is_none() && f.sig.abi.is_none()
&& f.sig.inputs.is_empty()
&& f.sig.generics.params.is_empty() && f.sig.generics.params.is_empty()
&& f.sig.generics.where_clause.is_none() && f.sig.generics.where_clause.is_none()
&& match f.sig.output { && match f.sig.output {
ReturnType::Type(_, ref ty) => matches!(**ty, Type::Never(_)), ReturnType::Type(_, ref ty) => matches!(**ty, Type::Never(_)),
_ => false, _ => false,
}, },
"#[agb::entry] must have signature [unsafe] fn () -> !" "#[agb::entry] must have signature [unsafe] fn (mut agb::Gba) -> !"
); );
// Check that the function signature takes 1 argument, agb::Gba
let arguments: Vec<_> = f.sig.inputs.iter().collect();
assert_eq!(
arguments.len(),
1,
"#[agb::entry] must have signature [unsafe] fn (mut agb::Gba) -> !, but got {} arguments",
arguments.len(),
);
let (argument_type, (argument_name, is_mutable)) = match arguments[0] {
FnArg::Typed(pat_type) => (
pat_type.ty.to_token_stream(),
match &*pat_type.pat {
Pat::Ident(ident) => {
assert!(
ident.attrs.is_empty() && ident.by_ref.is_none() && ident.subpat.is_none(),
"#[agb::entry] must have signature [unsafe] fn (mut agb::Gba) -> !"
);
(ident.ident.clone(), ident.mutability.is_some())
}
_ => panic!("Expected first argument to #[agb::entry] to be a basic identifier"),
},
),
_ => panic!("Expected first argument to #[agb::entry] to not be self"),
};
assert!( assert!(
args.to_string() == "", args.to_string() == "",
"Must pass no args to #[agb::entry] macro" "Must pass no args to #[agb::entry] macro"
@ -35,10 +62,23 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
let attrs = f.attrs; let attrs = f.attrs;
let stmts = f.block.stmts; let stmts = f.block.stmts;
let mutable = if is_mutable {
Some(Token![mut](Span::call_site()))
} else {
None
};
assert!(
argument_type.to_string().ends_with("Gba"),
"Expected first argument to have type 'Gba'"
);
quote!( quote!(
#[export_name = "main"] #[export_name = "main"]
#(#attrs)* #(#attrs)*
pub fn #fn_name() -> ! { pub fn #fn_name() -> ! {
let #mutable #argument_name = #argument_type ::new();
#(#stmts)* #(#stmts)*
} }
) )