From e6447cb08fb395a5da205bceb238bec302eae414 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sat, 7 Aug 2021 16:24:19 +0100 Subject: [PATCH] Add a simple entrypoint macro --- agb-entrypoint/Cargo.lock | 123 ++++++++++++++++++++++++++++++++++++++ agb-entrypoint/Cargo.toml | 16 +++++ agb-entrypoint/src/lib.rs | 60 +++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 agb-entrypoint/Cargo.lock create mode 100644 agb-entrypoint/Cargo.toml create mode 100644 agb-entrypoint/src/lib.rs diff --git a/agb-entrypoint/Cargo.lock b/agb-entrypoint/Cargo.lock new file mode 100644 index 00000000..a7feb091 --- /dev/null +++ b/agb-entrypoint/Cargo.lock @@ -0,0 +1,123 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "agb-entrypoint" +version = "0.6.0" +dependencies = [ + "proc-macro2", + "quote", + "rand", + "syn", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "syn" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/agb-entrypoint/Cargo.toml b/agb-entrypoint/Cargo.toml new file mode 100644 index 00000000..4e2567ba --- /dev/null +++ b/agb-entrypoint/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "agb-entrypoint" +version = "0.6.0" +authors = ["Gwilym Kuiper "] +edition = "2018" +license = "MPL-2.0" +description = "Macro for declaring the entrypoint for a game using the agb library" + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1.0.73", features = ["full", "extra-traits"] } +proc-macro2 = "1.0.27" +quote = "1.0.9" +rand = "0.8.4" \ No newline at end of file diff --git a/agb-entrypoint/src/lib.rs b/agb-entrypoint/src/lib.rs new file mode 100644 index 00000000..8312d98b --- /dev/null +++ b/agb-entrypoint/src/lib.rs @@ -0,0 +1,60 @@ +// This macro is based very heavily on the entry one in rust-embedded +use proc_macro::TokenStream; + +use proc_macro2::Span; +use quote::quote; +use syn::{ItemFn, ReturnType, Type, Visibility, Ident}; +use rand; +use rand::Rng; + +#[proc_macro_attribute] +pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { + let f: ItemFn = syn::parse(input).expect("#[agb::entry] must be applied to a function"); + + // Check that the function signature is correct + assert!( + 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) => match **ty { + Type::Never(_) => true, + _ => false, + }, + _ => false, + }, + "#[agb::entry] must have signature [unsafe] fn () -> !" + ); + + assert!(args.to_string() == "", "Must pass no args to entrypoint"); + + let fn_name = random_ident(); + + let attrs = f.attrs; + let stmts = f.block.stmts; + + quote!( + #[export_name = "main"] + #(#attrs)* + pub fn #fn_name() -> ! { + #(#stmts)* + } + ).into() +} + +fn random_ident() -> Ident { + let mut rng = rand::thread_rng(); + Ident::new( + &(0..16).map(|i| { + if i == 0 || rng.gen() { + ('a' as u8 + rng.gen::() % 25) as char + } else { + ('0' as u8 + rng.gen::() % 10) as char + } + }).collect::(), + Span::call_site() + ) +}