--- gforth/except.fs 2006/05/26 21:18:45 1.10 +++ gforth/except.fs 2010/08/31 20:10:59 1.22 @@ -1,12 +1,12 @@ \ catch, throw, etc. -\ Copyright (C) 1999,2000,2003 Free Software Foundation, Inc. +\ Copyright (C) 1999,2000,2003,2006,2007 Free Software Foundation, Inc. \ This file is part of Gforth. \ Gforth is free software; you can redistribute it and/or \ modify it under the terms of the GNU General Public License -\ as published by the Free Software Foundation; either version 2 +\ as published by the Free Software Foundation, either version 3 \ of the License, or (at your option) any later version. \ This program is distributed in the hope that it will be useful, @@ -15,19 +15,10 @@ \ GNU General Public License for more details. \ You should have received a copy of the GNU General Public License -\ along with this program; if not, write to the Free Software -\ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. +\ along with this program. If not, see http://www.gnu.org/licenses/. \ !! use a separate exception stack? anton -\ user-definable rollback actions - -Defer 'catch -Defer 'throw - -' noop IS 'catch -' noop IS 'throw - \ has? backtrace [IF] Defer store-backtrace ' noop IS store-backtrace @@ -76,10 +67,37 @@ Defer store-backtrace \ !! explain handler on-stack structure +Variable first-throw +: nothrow ( -- ) \ gforth + \G Use this (or the standard sequence @code{['] false catch drop}) + \G after a @code{catch} or @code{endtry} that does not rethrow; + \G this ensures that the next @code{throw} will record a + \G backtrace. + first-throw on ; + +: (try0) ( -- aoldhandler ) + first-throw on + handler @ ; + +[undefined] (try1) [if] +: (try1) ( aoldhandler arecovery -- anewhandler ) + r> + swap >r \ recovery address + sp@ cell+ >r + fp@ >r + lp@ >r + swap >r \ old handler + rp@ swap \ new handler + >r ; +[endif] + +: (try2) + handler ! ; + : (try) ( ahandler -- ) + first-throw on r> swap >r \ recovery address - rp@ 'catch >r sp@ >r fp@ >r lp@ >r @@ -87,72 +105,85 @@ Defer store-backtrace rp@ handler ! >r ; -: try ( compilation -- orig ; run-time -- ) \ gforth - \ !! does not work correctly for gforth-native +\ : try ( compilation -- orig ; run-time -- R:sys1 ) \ gforth +\ \G Start an exception-catching region. +\ POSTPONE ahead here >r >mark 1 cs-roll POSTPONE then +\ r> POSTPONE literal POSTPONE (try) ; immediate compile-only + +: try ( compilation -- orig ; run-time -- R:sys1 ) \ gforth + \G Start an exception-catching region. POSTPONE ahead here >r >mark 1 cs-roll POSTPONE then - r> POSTPONE literal POSTPONE (try) ; immediate compile-only + POSTPONE (try0) r> POSTPONE literal POSTPONE (try1) POSTPONE (try2) +; immediate compile-only + -: (recover) ( -- ) +: (endtry) ( -- ) \ normal end of try block: restore handler, forget rest r> r> handler ! rdrop \ lp rdrop \ fp rdrop \ sp - r> rp! rdrop \ recovery address >r ; -: recover ( compilation orig1 -- orig2 ; run-time -- ) \ gforth - \ !! check using a special tag - POSTPONE (recover) - POSTPONE else +: handler-intro, ( -- ) docol: here 0 , 0 , code-address! \ start a colon def postpone rdrop \ drop the return address +; + +: iferror ( compilation orig1 -- orig2 ; run-time -- ) \ gforth + \G Starts the exception handling code (executed if there is an + \G exception between @code{try} and @code{endtry}). This part has + \G to be finished with @code{then}. + \ !! check using a special tag + POSTPONE else handler-intro, +; immediate compile-only + +: restore ( compilation orig1 -- ; run-time -- ) \ gforth + \G Starts restoring code, that is executed if there is an + \G exception, and if there is no exception. + POSTPONE iferror POSTPONE then +; immediate compile-only + +: endtry ( compilation -- ; run-time R:sys1 -- ) \ gforth + \G End an exception-catching region. + POSTPONE (endtry) ; immediate compile-only -: endtry ( compilation orig -- ; run-time -- ) \ gforth - POSTPONE then ; immediate compile-only +: endtry-iferror ( compilation orig1 -- orig2 ; run-time R:sys1 -- ) \ gforth + \G End an exception-catching region while starting + \G exception-handling code outside that region (executed if there + \G is an exception between @code{try} and @code{endtry-iferror}). + \G This part has to be finished with @code{then} (or + \G @code{else}...@code{then}). + POSTPONE (endtry) POSTPONE iferror POSTPONE (endtry) +; immediate compile-only :noname ( x1 .. xn xt -- y1 .. ym 0 / z1 .. zn error ) \ exception try execute 0 - recover - nip - endtry ; + iferror + nip + then endtry ; is catch :noname ( y1 .. ym error/0 -- y1 .. ym / z1 .. zn error ) \ exception ?DUP IF [ here forthstart 9 cells + ! ] - store-backtrace error-stack off - handler @ ?dup-0=-IF - >stderr cr ." uncaught exception: " .error cr - 2 (bye) -\ quit + first-throw @ IF + store-backtrace error-stack off + first-throw off THEN - rp! - r> handler ! - r> lp! - r> fp! - r> swap >r sp! drop r> - rdrop 'throw r> perform - THEN ; -is throw -[IFDEF] throw>error -:noname ( y1 .. ym error/0 -- y1 .. ym / z1 .. zn error ) \ exception - ?DUP IF handler @ ?dup-0=-IF >stderr cr ." uncaught exception: " .error cr 2 (bye) \ quit THEN - rp! - r> handler ! - r> lp! - r> fp! - r> swap >r sp! drop r> - rdrop 'throw r> perform + dup rp! ( ... ball frame ) + cell+ dup @ lp! + cell+ dup @ fp! + cell+ dup @ ( ... ball addr sp ) -rot 2>r sp! drop 2r> + cell+ @ perform THEN ; -is throw>error -[THEN] \ No newline at end of file +is throw