File:  [gforth] / gforth / except.fs
Revision 1.20: download - view: text, annotated - select for diffs
Mon Dec 31 17:34:58 2007 UTC (16 years, 3 months ago) by anton
Branches: MAIN
CVS tags: HEAD
updated copyright years

    1: \ catch, throw, etc.
    2: 
    3: \ Copyright (C) 1999,2000,2003,2006,2007 Free Software Foundation, Inc.
    4: 
    5: \ This file is part of Gforth.
    6: 
    7: \ Gforth is free software; you can redistribute it and/or
    8: \ modify it under the terms of the GNU General Public License
    9: \ as published by the Free Software Foundation; either version 2
   10: \ of the License, or (at your option) any later version.
   11: 
   12: \ This program is distributed in the hope that it will be useful,
   13: \ but WITHOUT ANY WARRANTY; without even the implied warranty of
   14: \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15: \ GNU General Public License for more details.
   16: 
   17: \ You should have received a copy of the GNU General Public License
   18: \ along with this program; if not, write to the Free Software
   19: \ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
   20: 
   21: \ !! use a separate exception stack?           anton
   22: 
   23: \ has? backtrace [IF]
   24: Defer store-backtrace
   25: ' noop IS store-backtrace
   26: \ [THEN]
   27: 
   28: \ Ok, here's the story about how we get to the native code for the
   29: \ recovery code in case of a THROW, and why there is all this funny
   30: \ stuff being compiled by TRY and RECOVER:
   31: 
   32: \ Upon a THROW, we cannot just return through the ordinary return
   33: \ address, but have to use a different one, for code after the
   34: \ RECOVER.  How do we do that, in a way portable between the various
   35: \ threaded and native code engines?  In particular, how does the
   36: \ native code engine learn about the address of the native recovery
   37: \ code?
   38: 
   39: \ On the Forth level, we can compile only references to threaded code.
   40: \ The only thing that translates a threaded code address to a native
   41: \ code address is docol, which is only called with EXECUTE and
   42: \ friends.  So we start the recovery code with a docol, and invoke it
   43: \ with PERFORM; the recovery code then rdrops the superfluously
   44: \ generated return address and continues with the proper recovery
   45: \ code.
   46: 
   47: \ At compile time, since we cannot compile a forward reference (to the
   48: \ recovery code) as a literal (backpatching does not work for
   49: \ native-code literals), we produce a data cell (wrapped in AHEAD
   50: \ ... THEN) that we can backpatch, and compile the address of that as
   51: \ literal.
   52: 
   53: \ Overall, this leads to the following resulting code:
   54: 
   55: \   ahead
   56: \ +><recovery address>-+
   57: \ | then               |
   58: \ +-lit                |
   59: \   (try)              |
   60: \   ...                |
   61: \   (recover)          |
   62: \   ahead              |
   63: \   docol: <-----------+
   64: \   rdrop
   65: \   ...
   66: \   then
   67: \   ...
   68: 
   69: \ !! explain handler on-stack structure
   70: 
   71: Variable first-throw
   72: : nothrow ( -- ) \ gforth
   73:     \G Use this (or the standard sequence @code{['] false catch drop})
   74:     \G after a @code{catch} or @code{endtry} that does not rethrow;
   75:     \G this ensures that the next @code{throw} will record a
   76:     \G backtrace.
   77:     first-throw on ;
   78: 
   79: : (try) ( ahandler -- )
   80:     first-throw on
   81:     r>
   82:     swap >r \ recovery address
   83:     sp@ >r
   84:     fp@ >r
   85:     lp@ >r
   86:     handler @ >r
   87:     rp@ handler !
   88:     >r ;
   89: 
   90: : try ( compilation  -- orig ; run-time  -- R:sys1 ) \ gforth
   91:     \G Start an exception-catching region.
   92:     POSTPONE ahead here >r >mark 1 cs-roll POSTPONE then
   93:     r> POSTPONE literal POSTPONE (try) ; immediate compile-only
   94: 
   95: : (endtry) ( -- )
   96:     \ normal end of try block: restore handler, forget rest
   97:     r>
   98:     r> handler !
   99:     rdrop \ lp
  100:     rdrop \ fp
  101:     rdrop \ sp
  102:     rdrop \ recovery address
  103:     >r ;
  104: 
  105: : handler-intro, ( -- )
  106:     docol: here 0 , 0 , code-address! \ start a colon def 
  107:     postpone rdrop                    \ drop the return address
  108: ;
  109: 
  110: : iferror ( compilation  orig1 -- orig2 ; run-time  -- ) \ gforth
  111:     \G Starts the exception handling code (executed if there is an
  112:     \G exception between @code{try} and @code{endtry}).  This part has
  113:     \G to be finished with @code{then}.
  114:     \ !! check using a special tag
  115:     POSTPONE else handler-intro,
  116: ; immediate compile-only
  117: 
  118: : restore ( compilation  orig1 -- ; run-time  -- ) \ gforth
  119:     \G Starts restoring code, that is executed if there is an
  120:     \G exception, and if there is no exception.
  121:     POSTPONE iferror POSTPONE then
  122: ; immediate compile-only
  123: 
  124: : endtry ( compilation  -- ; run-time  R:sys1 -- ) \ gforth
  125:     \G End an exception-catching region.
  126:     POSTPONE (endtry)
  127: ; immediate compile-only
  128: 
  129: : endtry-iferror ( compilation  orig1 -- orig2 ; run-time  R:sys1 -- ) \ gforth
  130:     \G End an exception-catching region while starting
  131:     \G exception-handling code outside that region (executed if there
  132:     \G is an exception between @code{try} and @code{endtry-iferror}).
  133:     \G This part has to be finished with @code{then} (or
  134:     \G @code{else}...@code{then}).
  135:     POSTPONE (endtry) POSTPONE iferror POSTPONE (endtry)
  136: ; immediate compile-only
  137: 
  138: :noname ( x1 .. xn xt -- y1 .. ym 0 / z1 .. zn error ) \ exception
  139:     try
  140: 	execute 0
  141:     iferror
  142: 	nip
  143:     then endtry ;
  144: is catch
  145: 
  146: :noname ( y1 .. ym error/0 -- y1 .. ym / z1 .. zn error ) \ exception
  147:     ?DUP IF
  148: 	[ here forthstart 9 cells + ! ]
  149: 	first-throw @ IF
  150: 	    store-backtrace error-stack off
  151: 	    first-throw off
  152: 	THEN
  153: 	handler @ ?dup-0=-IF
  154: 	    >stderr cr ." uncaught exception: " .error cr
  155: 	    2 (bye)
  156: \	    quit
  157: 	THEN
  158:         dup rp! ( ... ball frame )
  159:         cell+ dup @ lp!
  160:         cell+ dup @ fp!
  161:         cell+ dup @ ( ... ball addr sp ) -rot 2>r sp! drop 2r>
  162:         cell+ @ perform
  163:     THEN ;
  164: is throw

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>