From 0d623fc5b00d37e899bdec35d05e0daec7a99708 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sun, 16 Jan 2022 21:38:04 +0000 Subject: [PATCH] Pass a Gba struct argument to the agb entry --- agb-macros/src/lib.rs | 48 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/agb-macros/src/lib.rs b/agb-macros/src/lib.rs index a00985eb..b20b52f7 100644 --- a/agb-macros/src/lib.rs +++ b/agb-macros/src/lib.rs @@ -2,9 +2,9 @@ use proc_macro::TokenStream; use proc_macro2::Span; -use quote::quote; +use quote::{quote, ToTokens}; use rand::Rng; -use syn::{Ident, ItemFn, ReturnType, Type, Visibility}; +use syn::{FnArg, Ident, ItemFn, Pat, ReturnType, Token, Type, Visibility}; #[proc_macro_attribute] 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.vis == Visibility::Inherited && f.sig.abi.is_none() - && f.sig.inputs.is_empty() && f.sig.generics.params.is_empty() && f.sig.generics.where_clause.is_none() && match f.sig.output { ReturnType::Type(_, ref ty) => matches!(**ty, Type::Never(_)), _ => 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!( args.to_string() == "", "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 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!( #[export_name = "main"] #(#attrs)* pub fn #fn_name() -> ! { + let #mutable #argument_name = #argument_type ::new(); + #(#stmts)* } )