Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::util::macros::compile_error_with;
use proc_macro2::TokenStream as MacroStream;

pub fn auto_bind_plugin_inner(attr: MacroStream, input: MacroStream) -> syn::Result<MacroStream> {
Expand Down Expand Up @@ -29,5 +30,6 @@ pub fn auto_bind_plugin_inner(attr: MacroStream, input: MacroStream) -> syn::Res
}

pub fn auto_bind_plugin_outer(attr: MacroStream, input: MacroStream) -> MacroStream {
auto_bind_plugin_inner(attr, input).unwrap_or_else(|err| err.to_compile_error())
let og_input = input.clone();
auto_bind_plugin_inner(attr, input).unwrap_or_else(|err| compile_error_with!(err, og_input))
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::util::macros::parse_macro_input2;
use crate::util::macros::{compile_error_with, ok_or_emit_with, parse_macro_input2_or_emit_with};
use proc_macro2::TokenStream as MacroStream;
use syn::ItemFn;

Expand All @@ -9,11 +9,9 @@ pub fn expand_auto_plugin(attr: MacroStream, input: MacroStream) -> MacroStream
use quote::quote;
use syn::spanned::Spanned;
use syn::{FnArg, parse2};
let item = parse_macro_input2!(input as ItemFn);
let params = match parse2::<AutoPluginFnArgs>(attr) {
Ok(params) => params,
Err(err) => return err.into_compile_error(),
};
let og_input = input.clone();
let item = parse_macro_input2_or_emit_with!(input as ItemFn, og_input);
let params = ok_or_emit_with!(parse2::<AutoPluginFnArgs>(attr), og_input);
let vis = &item.vis;
let attrs = &item.attrs;
let sig = &item.sig;
Expand All @@ -31,42 +29,48 @@ pub fn expand_auto_plugin(attr: MacroStream, input: MacroStream) -> MacroStream
let self_arg = self_args.first();

// TODO: use helper
let app_param_ident = match resolve_app_param_name(&item, params.app_param.as_ref()) {
Ok(ident) => ident,
Err(err) => return err.into_compile_error(),
};
let app_param_ident = ok_or_emit_with!(
resolve_app_param_name(&item, params.app_param.as_ref()),
og_input
);

if let Err(err) = require_fn_param_mutable_reference(&item, app_param_ident, "bevy app") {
return err.to_compile_error();
return compile_error_with!(err, og_input);
}

let mut impl_plugin = quote! {};

let auto_plugin_hook = if let Some(self_arg) = self_arg {
if params.plugin.is_some() {
return syn::Error::new(
params.plugin.span(),
"auto_plugin on trait impl can't specify plugin ident",
)
.to_compile_error();
return compile_error_with!(
syn::Error::new(
params.plugin.span(),
"auto_plugin on trait impl can't specify plugin ident",
),
og_input
);
};
quote! {
<Self as ::bevy_auto_plugin::__private::shared::__private::auto_plugin_registry::AutoPlugin>::build(#self_arg, #app_param_ident);
}
} else {
if sig.inputs.len() > 1 {
return syn::Error::new(
sig.inputs.span(),
"auto_plugin on bare fn can only accept a single parameter with the type &mut bevy::prelude::App",
)
.to_compile_error();
return compile_error_with!(
syn::Error::new(
sig.inputs.span(),
"auto_plugin on bare fn can only accept a single parameter with the type &mut bevy::prelude::App",
),
og_input
);
}
let Some(plugin_ident) = params.plugin else {
return syn::Error::new(
params.plugin.span(),
"auto_plugin on bare fn requires the plugin ident to be specified",
)
.to_compile_error();
return compile_error_with!(
syn::Error::new(
params.plugin.span(),
"auto_plugin on bare fn requires the plugin ident to be specified",
),
og_input
);
};
impl_plugin.extend(quote! {
impl ::bevy_auto_plugin::__private::shared::__private::auto_plugin_registry::bevy_app::Plugin for #plugin_ident {
Expand Down
14 changes: 7 additions & 7 deletions crates/bevy_auto_plugin_shared/src/__private/expand/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::macro_api::attributes::ItemAttributeArgs;
use crate::macro_api::attributes::prelude::*;
use crate::macro_api::with_plugin::{PluginBound, WithPlugin};
use crate::syntax::diagnostic::kind::item_kind;
use crate::util::macros::ok_or_return_compiler_error;
use crate::util::macros::ok_or_emit_with;
use darling::FromMeta;
use proc_macro2::{Ident, Span, TokenStream as MacroStream};
use quote::{format_ident, quote};
Expand Down Expand Up @@ -56,20 +56,20 @@ where
let input = input.into();

// need to clone input so we can pass through input untouched for optimal IDE support
let item: Item = ok_or_return_compiler_error!(parse2(input.clone()));
let item: Item = ok_or_emit_with!(parse2(input.clone()), input);

let err_msg = format!("Attribute macro is not allowed on {}", item_kind(&item));
let ident = ok_or_return_compiler_error!(
let ident = ok_or_emit_with!(
resolve_ident(&item).map_err(|e| {
// make sure the call_site span is used instead so the user knows what attribute caused the error
syn::Error::new(Span::call_site(), e)
}),
err_msg
input,
format!("Attribute macro is not allowed on {}", item_kind(&item))
);

let args = ok_or_return_compiler_error!(parse_attr(attr));
let args = ok_or_emit_with!(parse_attr(attr), input);

let output = ok_or_return_compiler_error!(body(ident, args, &item));
let output = ok_or_emit_with!(body(ident, args, &item), input);

quote! {
#input
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::util::macros::parse_macro_input2;
use crate::util::macros::{ok_or_emit, parse_macro_input2};
use proc_macro2::TokenStream as MacroStream;

pub fn expand_derive_auto_plugin(input: MacroStream) -> MacroStream {
Expand Down Expand Up @@ -33,10 +33,7 @@ pub fn expand_derive_auto_plugin(input: MacroStream) -> MacroStream {
.collect()
};
for full_name in full_names {
let path_with_generics = match syn::parse_str::<syn::Path>(&full_name) {
Ok(p) => p,
Err(err) => return err.into_compile_error(),
};
let path_with_generics = ok_or_emit!(syn::parse_str::<syn::Path>(&full_name));

auto_plugin_implemented = true;

Expand Down
122 changes: 112 additions & 10 deletions crates/bevy_auto_plugin_shared/src/util/macros.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,52 @@
macro_rules! ok_or_return_compiler_error {
// Case: expression, message
($expr:expr, $message:expr) => {{
macro_rules! compile_error_with {
($err:expr, $user_tokens:expr $(,)?) => {{
let ce = $err.to_compile_error();
let tokens = $user_tokens;
::quote::quote!( #ce #tokens )
}};
}

macro_rules! ok_or_emit {
// Case: expression, tokens, message
($expr:expr, $message:expr $(,)?) => {{
let message = $message;
match $expr {
Ok(v) => v,
Err(e) => {
return syn::Error::new(e.span(), format!("{message}: {e}"))
.to_compile_error()
.into();
return ::syn::Error::new(e.span(), format!("{message}: {e}")).to_compile_error();
}
}
}};
// Case: Only expression
// Case: Only expression + tokens
($expr:expr) => {{
match $expr {
Ok(v) => v,
Err(e) => return e.to_compile_error(),
}
}};
}

macro_rules! ok_or_emit_with {
// Case: Only expression + tokens
($expr:expr, $user_tokens:expr $(,)?) => {{
match $expr {
Ok(v) => v,
Err(e) => {
return e.to_compile_error().into();
let ce = e.to_compile_error();
let tokens = $user_tokens;
return ::quote::quote!( #ce #tokens )
}
}
}};
// Case: expression, tokens, message
($expr:expr, $user_tokens:expr, $message:expr $(,)?) => {{
let message = $message;
match $expr {
Ok(v) => v,
Err(e) => {
let ce = ::syn::Error::new(e.span(), format!("{message}: {e}")).to_compile_error();
let tokens = $user_tokens;
return ::quote::quote!( #ce #tokens )
}
}
}};
Expand All @@ -31,6 +61,15 @@ macro_rules! parse_macro_input2 {
}};
}

macro_rules! parse_macro_input2_or_emit_with {
($ts:ident as $ty:ty, $user_tokens:expr $(,)?) => {{
match ::syn::parse2::<$ty>($ts) {
Ok(v) => v,
Err(e) => return $crate::util::macros::compile_error_with!(e, $user_tokens),
}
}};
}

macro_rules! as_cargo_alias {
($name:ident) => {
::syn::Ident::new(&$name, ::proc_macro2::Span::call_site())
Expand Down Expand Up @@ -82,8 +121,11 @@ macro_rules! bevy_crate_path {

#[rustfmt::skip]
pub(crate) use {
ok_or_return_compiler_error,
compile_error_with,
ok_or_emit,
ok_or_emit_with,
parse_macro_input2,
parse_macro_input2_or_emit_with,
as_cargo_alias,
bevy_crate_path,
};
Expand All @@ -92,7 +134,8 @@ pub(crate) use {
mod tests {
use super::*;
use internal_test_proc_macro::xtest;
use quote::ToTokens;
use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote};

#[xtest]
fn test_bevy_crate_path() {
Expand All @@ -105,4 +148,63 @@ mod tests {
expected_path
)
}

#[test]
fn test_ok_or_emit_ok() {
fn process(ts: syn::Result<TokenStream>) -> TokenStream {
ok_or_emit!(ts)
}
assert_eq!(
process(Ok(quote! { foo_bar })).to_string(),
quote! { foo_bar }.to_string()
);
}

#[test]
fn test_ok_or_emit_err() {
fn process(ts: syn::Result<TokenStream>) -> TokenStream {
ok_or_emit!(ts)
}
assert_eq!(
process(Err(syn::Error::new(Span::call_site(), "error"))).to_string(),
quote! { :: core :: compile_error ! { "error" } }.to_string()
);
}

#[xtest]
fn test_ok_or_emit_with_ok() {
let input = quote! {
let a = 1;
let b = 2;
let c = 3;
};

let expected = quote! {
let foo = 4
};
fn process(ts: TokenStream, expected: &TokenStream) -> TokenStream {
ok_or_emit_with!(syn::Result::Ok(quote! { # expected }), ts)
}

assert_eq!(process(input, &expected).to_string(), expected.to_string());
}

#[xtest]
fn test_ok_or_emit_with_err() {
let input = quote! {
let a = 1;
let b = 2;
let c = 3;
};
fn process(ts: TokenStream) -> TokenStream {
ok_or_emit_with!(Err(syn::Error::new(Span::call_site(), "error")), ts)
}

let expected = quote! {
:: core :: compile_error ! { "error" }
#input
};

assert_eq!(process(input).to_string(), expected.to_string());
}
}