File:  [gforth] / gforth / except.fs
Revision 1.21: download - view: text, annotated - select for diffs
Mon Dec 31 18:40:24 2007 UTC (12 years, 1 month ago) by anton
Branches: MAIN
CVS tags: v0-7-0, HEAD
updated copyright notices for GPL v3

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

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