@@ -2015,9 +2015,35 @@ impl LuaVM {
20152015 // ===== Lightweight Error Handling API =====
20162016
20172017 /// Set runtime error and return lightweight error enum
2018- # [ inline ]
2018+ /// If an error handler is set (via xpcall), it will be called immediately
20192019 pub fn error ( & mut self , message : impl Into < String > ) -> LuaError {
2020- self . error_message = message. into ( ) ;
2020+ let msg = message. into ( ) ;
2021+
2022+ // Check if there's an error handler (set by xpcall)
2023+ if let Some ( handler) = self . error_handler . clone ( ) {
2024+ // Call the error handler with the error message
2025+ // Note: The call stack is still intact at this point
2026+ let err_value = self . create_string ( & msg) ;
2027+
2028+ match self . call_function_internal ( handler, vec ! [ err_value] ) {
2029+ Ok ( handler_results) => {
2030+ // Error handler succeeded, use its return value as the new error message
2031+ if let Some ( result) = handler_results. first ( ) {
2032+ self . error_message = self . value_to_string_raw ( result) ;
2033+ } else {
2034+ self . error_message = msg;
2035+ }
2036+ }
2037+ Err ( _) => {
2038+ // Error handler itself failed, use original message
2039+ self . error_message = format ! ( "error in error handler: {}" , msg) ;
2040+ }
2041+ }
2042+ } else {
2043+ // No error handler, just set the message
2044+ self . error_message = msg;
2045+ }
2046+
20212047 LuaError :: RuntimeError
20222048 }
20232049
@@ -2413,58 +2439,43 @@ impl LuaVM {
24132439 }
24142440 }
24152441
2416- /// Protected call with error handler
2442+ /// Protected call with error handler (xpcall semantics)
2443+ /// The error handler is registered and will be called by error() when an error occurs
24172444 /// Note: Yields are NOT caught by xpcall - they propagate through
24182445 pub fn protected_call_with_handler (
24192446 & mut self ,
24202447 func : LuaValue ,
24212448 args : Vec < LuaValue > ,
24222449 err_handler : LuaValue ,
24232450 ) -> LuaResult < ( bool , Vec < LuaValue > ) > {
2451+ // Save old error handler and set the new one
24242452 let old_handler = self . error_handler . clone ( ) ;
24252453 self . error_handler = Some ( err_handler. clone ( ) ) ;
24262454
24272455 let initial_frame_count = self . frame_count ;
24282456
2457+ // Call the function - if it errors, error() will call the handler
24292458 let result = self . call_function_internal ( func, args) ;
24302459
2460+ // Restore old error handler
24312461 self . error_handler = old_handler;
24322462
24332463 match result {
24342464 Ok ( values) => Ok ( ( true , values) ) ,
24352465 Err ( LuaError :: Yield ) => Err ( LuaError :: Yield ) ,
24362466 Err ( _) => {
2437- // IMPORTANT: For xpcall, we call the error handler BEFORE cleaning up frames
2438- // This allows the handler to access the full call stack for traceback generation
2439-
2440- // Get the error message (which already includes traceback)
2441- let msg = self . error_message . clone ( ) ;
2442- let err_value = self . create_string ( & msg) ;
2443- let err_display = format ! ( "Runtime Error: {}" , msg) ;
2444-
2445- // Call error handler with the error message BEFORE cleaning up frames
2446- let handler_result = self . call_function_internal ( err_handler, vec ! [ err_value] ) ;
2447-
2448- // NOW clean up frames created by the failed function call
2467+ // Error occurred (and handler was already called in error())
2468+ // Clean up frames created by the failed function call
24492469 while self . frame_count > initial_frame_count {
24502470 let frame = self . pop_frame ( ) . unwrap ( ) ;
24512471 // Close upvalues belonging to this frame
24522472 self . close_upvalues_from ( frame. base_ptr ) ;
24532473 }
2454-
2455- match handler_result {
2456- Ok ( handler_values) => Ok ( ( false , handler_values) ) ,
2457- Err ( LuaError :: Yield ) => {
2458- // Yield from error handler - propagate it
2459- let values = self . take_yield_values ( ) ;
2460- Err ( self . do_yield ( values) )
2461- }
2462- Err ( _) => {
2463- let err_str =
2464- self . create_string ( & format ! ( "Error in error handler: {}" , err_display) ) ;
2465- Ok ( ( false , vec ! [ err_str] ) )
2466- }
2467- }
2474+
2475+ // Return the error message (which may have been modified by the handler)
2476+ let msg = self . error_message . clone ( ) ;
2477+ let err_str = self . create_string ( & msg) ;
2478+ Ok ( ( false , vec ! [ err_str] ) )
24682479 }
24692480 }
24702481 }
0 commit comments