diff --git a/Cargo.lock b/Cargo.lock index 8beb98920..536eb8c85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1039,6 +1039,7 @@ name = "fj" version = "0.41.0" dependencies = [ "anyhow", + "backtrace", "fj-proc", "serde", "serde_json", diff --git a/crates/fj-proc/src/lib.rs b/crates/fj-proc/src/lib.rs index 6566e247e..9c43aec92 100644 --- a/crates/fj-proc/src/lib.rs +++ b/crates/fj-proc/src/lib.rs @@ -2,11 +2,7 @@ mod expand; mod parse; use proc_macro::TokenStream; -use proc_macro2::{Ident, Span}; -use syn::{ - parse_macro_input, punctuated::Punctuated, token::Paren, Expr, ExprCall, - ExprPath, FnArg, ItemFn, PathArguments, PathSegment, Stmt, -}; +use syn::{parse_macro_input, FnArg, ItemFn}; /// Define a function-based model. /// @@ -95,58 +91,19 @@ pub fn model(_: TokenStream, input: TokenStream) -> TokenStream { match parse::parse(&item) { Ok(init) => { - let mut item = without_param_attrs(item); + let item = without_param_attrs(item); - // Yes, all of this is to add `fj::abi::initialize_panic_handling();` to the top of the function. - item.block.stmts.insert( - 0, - Stmt::Semi( - Expr::Call(ExprCall { - attrs: vec![], - func: Box::new(Expr::Path(ExprPath { - attrs: vec![], - qself: None, - path: syn::Path { - leading_colon: None, - segments: { - let mut segments = Punctuated::new(); + let attrs = item.attrs; + let vis = item.vis; + let sig = item.sig; + let statements = item.block.stmts; - segments.push(PathSegment { - ident: Ident::new( - "fj", - Span::call_site(), - ), - arguments: PathArguments::None, - }); - - segments.push(PathSegment { - ident: Ident::new( - "abi", - Span::call_site(), - ), - arguments: PathArguments::None, - }); - - segments.push(PathSegment { - ident: Ident::new( - "initialize_panic_handling", - Span::call_site(), - ), - arguments: PathArguments::None, - }); - - segments - }, - }, - })), - paren_token: Paren { - span: Span::call_site(), - }, - args: Punctuated::new(), - }), - syn::token::Semi::default(), - ), - ); + let item = quote::quote! { + #(#attrs)* #vis #sig { + fj::abi::initialize_panic_handling(); + #(#statements)* + } + }; let tokens = quote::quote! { #item @@ -154,8 +111,6 @@ pub fn model(_: TokenStream, input: TokenStream) -> TokenStream { }; - eprintln!("TOKENS: {}", tokens); - tokens.into() } Err(e) => e.into_compile_error().into(), diff --git a/crates/fj/Cargo.toml b/crates/fj/Cargo.toml index 7e99f949a..212278e7b 100644 --- a/crates/fj/Cargo.toml +++ b/crates/fj/Cargo.toml @@ -17,6 +17,7 @@ anyhow = "1.0.70" [dependencies] fj-proc.workspace = true +backtrace = "0.3.67" [dependencies.serde] version = "1.0.158" diff --git a/crates/fj/src/abi/mod.rs b/crates/fj/src/abi/mod.rs index f142539d4..d6e7c2363 100644 --- a/crates/fj/src/abi/mod.rs +++ b/crates/fj/src/abi/mod.rs @@ -43,6 +43,7 @@ mod host; mod metadata; mod model; +use backtrace::Backtrace; use std::{any::Any, fmt::Display, panic, sync::Mutex}; pub use self::{ @@ -122,6 +123,7 @@ pub const INIT_FUNCTION_NAME: &str = "fj_model_init"; struct PanicInfo { message: Option, location: Option, + backtrace: Backtrace, } impl Display for PanicInfo { @@ -139,6 +141,8 @@ impl Display for PanicInfo { write!(f, "no location given")?; } + writeln!(f, "\nBacktrace:\n{:?}", self.backtrace)?; + Ok(()) } } @@ -180,7 +184,12 @@ pub fn initialize_panic_handling() { column: location.column(), }); - *last_panic = Some(PanicInfo { message, location }); + let backtrace = backtrace::Backtrace::new(); + *last_panic = Some(PanicInfo { + message, + location, + backtrace, + }); })); }