Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
112 changes: 16 additions & 96 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ stacksafe = { version = "1.0.1", path = "stacksafe" }
stacksafe-macro = { version = "=1.0.1", path = "stacksafe-macro" }

# crates.io dependencies
proc-macro-error2 = { version = "2" }
quote = { version = "1" }
serde = { version = "1" }
stacker = { version = "0.1" }
syn = { version = "2" }
proc-macro2 = { version = "1.0.106" }
quote = { version = "1.0.45" }
serde = { version = "1.0.228" }
stacker = { version = "0.1.24" }
syn = { version = "2.0.117" }
2 changes: 1 addition & 1 deletion stacksafe-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ version.workspace = true
proc-macro = true

[dependencies]
proc-macro-error2 = { workspace = true }
proc-macro2 = { workspace = true }
quote = { workspace = true }
syn = { workspace = true, features = ["full"] }
47 changes: 30 additions & 17 deletions stacksafe-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,32 @@
//! This crate provides the `#[stacksafe]` attribute macro that transforms functions
//! to use automatic stack growth, preventing stack overflow in deeply recursive scenarios.

use proc_macro::TokenStream;
use proc_macro_error2::abort;
use proc_macro_error2::abort_call_site;
use proc_macro_error2::proc_macro_error;
use proc_macro2::Span;
use proc_macro2::TokenStream;
use quote::ToTokens;
use quote::quote;
use syn::ItemFn;
use syn::Path;
use syn::ReturnType;
use syn::Type;
use syn::parse_macro_input;
use syn::parse_quote;
use syn::spanned::Spanned;

#[proc_macro_attribute]
#[proc_macro_error]
pub fn stacksafe(args: TokenStream, item: TokenStream) -> TokenStream {
let mut crate_path: Option<Path> = None;
pub fn stacksafe(
args: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let args = TokenStream::from(args);
let item = TokenStream::from(item);
match stacksafe_impl(args, item) {
Ok(tokens) => tokens.into(),
Err(err) => err.into_compile_error().into(),
}
}

fn stacksafe_impl(args: TokenStream, item: TokenStream) -> syn::Result<TokenStream> {
let mut crate_path: Option<Path> = None;
let arg_parser = syn::meta::parser(|meta| {
if meta.path.is_ident("crate") {
crate_path = Some(meta.value()?.parse()?);
Expand All @@ -48,18 +56,23 @@ pub fn stacksafe(args: TokenStream, item: TokenStream) -> TokenStream {
)))
}
});
parse_macro_input!(args with arg_parser);
syn::parse::Parser::parse2(arg_parser, args)?;

let item_fn: ItemFn = match syn::parse(item.clone()) {
let item_fn = match syn::parse2::<ItemFn>(item.clone()) {
Ok(item) => item,
Err(_) => abort_call_site!("#[stacksafe] can only be applied to functions"),
Err(_) => {
return Err(syn::Error::new(
Span::call_site(),
"#[stacksafe] can only be applied to functions",
));
}
};

if item_fn.sig.asyncness.is_some() {
abort!(
item_fn.sig.asyncness,
"#[stacksafe] does not support async functions"
);
return Err(syn::Error::new(
item_fn.sig.asyncness.span(),
"#[stacksafe] does not support async functions",
));
}

let mut item_fn = item_fn;
Expand All @@ -82,6 +95,6 @@ pub fn stacksafe(args: TokenStream, item: TokenStream) -> TokenStream {
}
};

*item_fn.block = syn::parse(wrapped_block.into()).unwrap();
item_fn.into_token_stream().into()
*item_fn.block = syn::parse(wrapped_block.into())?;
Ok(item_fn.into_token_stream())
}
Loading