PSL Manual                    7 February 1983   Error Handling and Recovery
section 14.0                                                      page 14.1

                                CHAPTER 14
                                CHAPTER 14
                                CHAPTER 14
                              ERROR HANDLING
                              ERROR HANDLING
                              ERROR HANDLING




     14.1. Introduction .  .  .  .  .  .  .  .  .  .  .  .  .  .  .    14.1
     14.2. The Basic Error Functions.  .  .  .  .  .  .  .  .  .  .    14.1
     14.3. Break Loop.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .    14.4
     14.4. Interrupt Keys  .  .  .  .  .  .  .  .  .  .  .  .  .  .    14.7
     14.5. Details on the Break Loop.  .  .  .  .  .  .  .  .  .  .    14.7
     14.6. Some Convenient Error Calls .  .  .  .  .  .  .  .  .  .    14.7
     14.7. Special Purpose Error Handlers .  .  .  .  .  .  .  .  .    14.9




14.1. Introduction
14.1. Introduction
14.1. Introduction

  In  PSL, as in most LISP systems, various kinds of errors are detected by
functions in the process of checking the validity of their  argument  types
and  other  conditions.   Errors are then "signalled" to a currently active
                      ErrorSet                  Error
                      ErrorSet                  Error
error handler (called ErrorSet) by a call on an Error function.    In  PSL,
                                                  Break
                                                  Break
the  error handler typically calls an interactive Break loop, which permits
the user to examine the context of  the  error  and  optionally  make  some
corrections and continue the computation, or to abort the computation.

                 Break
                 Break
  While  in  the Break loop, the user remains in the binding context of the
function that detected  the  error;  the  user  sees  the  value  of  FLUID
variables  as  they  are  in  the  function itself.  If the user aborts the
                       Throw
                       Throw
computation, a call on Throw with a tag of !$ERROR!$ is  done,  and  fluids
are unbound.

  [??? What about errors signalled to the Interrupt Handler ???]
  [??? What about errors signalled to the Interrupt Handler ???]
  [??? What about errors signalled to the Interrupt Handler ???]



14.2. The Basic Error Functions
14.2. The Basic Error Functions
14.2. The Basic Error Functions

  The  following  two  switches  and  one  global  variable are used by the
functions in this section.


             __________                                              ______
!*BACKTRACE [Initially: T]                                           switch

             ErrorSet
             ErrorSet
     Set in  ErrorSet.    Controls  whether  an  unwind  backtrace  is
     requested.
Error Handling and Recovery   7 February 1983                    PSL Manual
page 14.2                                                      section 14.2

        __________                                                   ______
!*MSGP [Initially: T]                                                switch

             ErrorSet
             ErrorSet
     Set  in ErrorSet.  Controls error message printing during call on
     error.


        __________                                                   ______
EMSG!* [Initially: NIL]                                              global

     Contains the message generated by the last error call.


 ErrorSet
 ErrorSet _ ___    ____ _______    _________ _______   ___             ____
(ErrorSet U:any  !*MSGP:boolean  !*BACKTRACE:boolean): any             expr

                                                               _
     If an uncorrected error occurs during the evaluation  of  U,  the
              ______
     value of NUMBER from the associated error call is returned as the
                                                       ____
                                                       ____
                                                       ____
                ErrorSet                ErrorSet       expr
                ErrorSet                ErrorSet       expr     _
     value  of  ErrorSet.    Note  that ErrorSet is an expr, so U gets
     evaluated twice, once as the parameter is passed and once  inside
     ErrorSet                  ErrorSet               Catch
     ErrorSet                  ErrorSet               Catch
     ErrorSet.     [Actually,  ErrorSet  executes  a  Catch  with  tag
                                        Throw
                                        Throw
     !$ERROR!$, and so intercepts  any  Throw  with  this  tag.]    In
     addition, if the value of !*MSGP is non-NIL, the message from the
     error  call is displayed upon both the standard output device and
     the currently selected output device unless the  standard  output
     device  is  not  open.    The  message  appears  prefixed  with 5
     asterisks.  The message  list  is  displayed  without  top  level
     parentheses.  The message from the error call is available in the
     GLOBAL  variable  EMSG!*.    The  exact  format of error messages
     generated by PSL functions described in this document may not  be
     exactly  as  given  and  should  not  be relied upon to be in any
     particular form.    Likewise,  error  numbers  generated  by  PSL
     functions  are not fixed.  Currently, a number of different calls
        Error
        Error
     on Error result in the same error message, since the cause of the
     error is the same and the information to the user  is  the  same.
     The error number is then used to indicate which function actually
     detected the error.  

       [???  Describe  Error  #  ranges  here,  or have in a file on
       [???  Describe  Error  #  ranges  here,  or have in a file on
       [???  Describe  Error  #  ranges  here,  or have in a file on
       machine ???]
       machine ???]
       machine ???]

                                                    _
     If no error occurs during the  evaluation  of  U,  the  value  of
      List  Eval
      List  Eval _
     (List (Eval U)) is returned.

     If  an  error  has been signalled and the value of !*BACKTRACE is
     non-NIL, a traceback sequence is initiated on the selected output
     device.  The traceback displays information such as unbindings of
     FLUID variables, argument lists and so on in an  implementation--
     dependent format.


 Error
 Error ______ _______  _______ ___   ____ ________                     ____
(Error NUMBER:integer  MESSAGE:any): None Returned                     expr

     _______
     MESSAGE  is  placed  in  the GLOBAL variable EMSG!* and the error
                                                    ErrorSet
                                                    ErrorSet
     number becomes the value of  the  surrounding  ErrorSet  (if  any
PSL Manual                    7 February 1983   Error Handling and Recovery
section 14.2                                                      page 14.3

                  Break
                  Break
     intervening  Break  loop  is  exited).  FLUID variables and LOCAL
     bindings  are  unbound  to  return  to  the  environment  of  the
     ErrorSet
     ErrorSet
     ErrorSet.    GLOBAL  variables  are  not affected by the process.
     Error                                                 Break
     Error                                                 Break
     Error actually signals a non-continuable error to the Break loop,
     and it subsequently does a throw with tag !$ERROR!$.


 ContinuableError
 ContinuableError ______ _______  _______ ___  ____ ____   ___         ____
(ContinuableError NUMBER:integer  MESSAGE:any  FORM:form): any         expr

     _______
     MESSAGE is placed in the GLOBAL variable  EMSG!*  and  the  error
                                                       ErrorSet
                                                       ErrorSet
     number  becomes  the  value  of  the  surrounding ErrorSet if the
                 Break
                 Break
     intervening Break loop  is  "QUIT"  rather  than  "Continued"  or
     "Retried".    FLUID  variables  and LOCAL bindings are unbound to
                                      ErrorSet
                                      ErrorSet
     return to the environment of the ErrorSet.  GLOBAL variables  are
                                           Error
                                           Error
     not   affected   by  the  process.    Error  actually  signals  a
                              Break
                              Break
     continuable error to the Break loop, and it subsequently  does  a
     throw with tag !$ERROR!$.

     The  FORM  is  stored  in  the  GLOBAL  variable ERRORFORM!*, for
     examination, editing  or  possible  reevaluation  after  defining
     missing functions, etc.  Setting up the ERRORFORM!* can get a bit
                                   MkQuote
                                   MkQuote
     tricky,   often   involving   MkQuoteing   of  already  evaluated
     arguments.  The following MACRO may be useful.


 ContError
 ContError  ____ ___    ___                                           _____
(ContError [ARGS:any]): any                                           macro

                   ____
     The format of ARGS is (ErrorNumber, FormatString,  {arguments  to
                                     ____________
     PrintF},   ReEvalForm).    The  FORMATSTRING  is  used  with  the
                                          BldMsg
                                          BldMsg
     following arguments in  a  call  on  BldMsg  to  build  an  error
                                              PrintF
                                              PrintF
     message.    If  the  only  argument  to  PrintF  is a string, the
                                                 BldMsg
     ____________                                BldMsg
     FORMATSTRING may be omitted, and no call to BldMsg is made.   The
     ReEvalForm  is  something like Foo(X, Y) which becomes list('Foo,
     MkQuote  X,  MkQuote  Y)   to   be   passed   to   the   function
     ContinuableError
     ContinuableError
     ContinuableError.

         (DE DIVIDE (U, V)
            (COND((ZEROP V)
                   (CONTERROR 99 "Attempt to divide by 0 in DIVIDE
                                                       (DIVIDE U V
                 (T (CONS (QUOTIENT U V) (REMAINDER U V)))))


                    __________                                       ______
!*CONTINUABLEERROR [Initially: NIL]                                  switch

           ________________
     If  !*CONTINUABLEERROR  is  T,  then  one is inside a continuable
     error.
Error Handling and Recovery   7 February 1983                    PSL Manual
page 14.4                                                      section 14.3

14.3. Break Loop
14.3. Break Loop
14.3. Break Loop

                                                Read/Eval/Print
                                                Read/Eval/Print
  On  detecting an error, PSL normally enters a Read/Eval/Print loop called
  Break
  Break
a Break loop.  Here the user can examine  the  state  of  his  computation,
change  the  values  of  FLUIDs,  or define missing functions.  He can then
                                                                   ErrorSet
                                                                   ErrorSet
dismiss the error call to the normal error handling mechanism (the ErrorSet
above) or (in some situations) continue the computation.   By  setting  the
                           Break
                           Break
switch !*BREAK to NIL, all Break loops can be suppressed, and just an error
message is displayed.


         __________                                                  ______
!*BREAK [Initially: T]                                               switch

                          Break
                          Break
     Controls whether the Break package is called before unwinding the
     stack on error.


              __________                                             ______
BREAKLEVEL!* [Initially: 0]                                          global

     The current number of nesting level of breaks.


                 __________                                          ______
MAXBREAKLEVEL!* [Initially: 5]                                       global

     The maximum number of nesting levels of breaks permitted.

                                                             Break
                                                             Break
  The  prompt  "Break>"  indicates  that  PSL  has entered a Break loop.  A
message of the form "Continuation requires a value for  ..."  may  also  be
printed,  in  which  case  the  user is able to continue his computation by
                                                     Break
                                                     Break
repairing the offending expression.  By default,  a  Break  loop  uses  the
           Read   Eval        Print
           Read   Eval        Print
functions  Read,  Eval,  and  Print.    This  may  be  changed  by  setting
BREAKREADER!*,  BREAKEVALUATOR!*,  or  BREAKPRINTER!*  to  the  appropriate
function name.


             __________                                              ______
ERRORFORM!* [Initially: NIL]                                         global

                                                        Break
                                                        Break
     Contains  an  expression  to  reevaluate  inside a Break loop for
     continuable errors.  [Not enough errors set this yet].  Used as a
     tag for various Error functions.

                                                       Break
          __                                           Break
  Several ids, if typed at top-level, are special in a Break loop.    These
are  used  as  commands, and are currently E, M, R, T, Q, A, I, and C. They
call  functions  stored  on  their  property  lists  under  the   indicator
                        __
'BreakFunction.   These ids are special only at top-level, and do not cause
any difficulty if used as variables inside expressions.  However, they  may
not be simply typed at top-level to see their values.  This is not expected
to  cause  any  difficulty.  If it does, an escape command will be provided
for examining the relevant variables.

  The meanings of these commands are:
PSL Manual                    7 February 1983   Error Handling and Recovery
section 14.3                                                      page 14.5

E         Edit the value of ERRORFORM!*.  This is the object printed in the
          "Continuation  requires  a  value for ..." message.  The function
          BreakEdit
          BreakEdit
          BreakEdit is the associated function called by this command.  The
          Retry
          Retry
          Retry command (below) uses the corrected version of  ERRORFORM!*.
          The currently available editors are described in Chapter 16.

                                                             BreakErrmsg
                                                             BreakErrmsg
M         Show the modified ERRORFORM!*.  Calls the function BreakErrmsg.

R         Retry.    This  tries to evaluate the offending expression again,
          and  continue  the  computation.    It  evaluates  the  value  of
          ERRORFORM!*.    This  is  often  useful  after defining a missing
                                                                       Edit
                                                                       Edit
          function, assigning a value to a  variable,  or  using  the  Edit
                                                           BreakRetry
                                                           BreakRetry
          command, above.  This command calls the function BreakRetry.

                                                           Break
                                                           Break
C         This  causes  the expression last printed by the Break loop to be
          returned as the value of the offending expression.  This is often
          useful as an automatic stub.   If  an  expression  containing  an
                                                 Break
                                                 Break
          undefined  function  is  evaluated,  a Break loop is entered, and
          this may be used to return the value of the function call.   This
                                     BreakContinue
                                     BreakContinue
          command calls the function BreakContinue.

                                     Break
                                     Break
Q         Quit.    This  exits  the  Break  loop by throwing to the closest
                      ErrorSet                         BreakQuit
                      ErrorSet                         BreakQuit
          surrounding ErrorSet.  It calls the function BreakQuit.

A         Abort.  This aborts to the top level, i.e.,  restarts  PSL.    It
                             Reset
                             Reset
          calls the function Reset.

T         Trace.    This  prints a backtrace of function calls on the stack
          except  for  those  on   the   lists   IGNOREDINBACKTRACE!*   and
                                                         BackTrace
                                                         BackTrace
          INTERPRETERFUNCTIONS!*.  It calls the function BackTrace.

I         Interpreter  Trace.   This prints a backtrace of only interpreted
          functions call  on  the  stack  except  for  those  on  the  list
                                                         InterpBackTrace
                                                         InterpBackTrace
          INTERPRETERFUNCTIONS!*.  It calls the function InterpBackTrace.


An attempt to continue a non-continuable error with R or C prints a message
and behaves as Q. 


                      __________
IGNOREDINBACKTRACE!* [Initially: '(Eval Apply FastApply CodeApply
CodeEvalApply  Catch ErrorSet EvProgN TopLoop BreakEval
                                                                     ______
BindEval Break Main)]                                                global

     A list of function names that will not be printed by the commands
                            Break
                            Break
     I and T given within a Break loop.


                        __________                                   ______
INTERPRETERFUNCTIONS!* [Initially: '(Cond Prog And Or ProgN SetQ)]   global

     A  list of function names that will not be printed by the command
                      Break
                      Break
     I given within a Break loop.
Error Handling and Recovery   7 February 1983                    PSL Manual
page 14.6                                                      section 14.3

  The  above  two  globals  can  be reset in an init file if the programmer
desires to do so.

  The following is a slightly edited transcript, showing some of the  BREAK
options:
PSL Manual                    7 February 1983   Error Handling and Recovery
section 14.3                                                      page 14.7

   % foo is an undefined function, so the following has two errors
   %   in it

   1> (Plus2 (foo 1)(foo 2))
   ***** `FOO' is an undefined function {1001}
   ***** Continuation requires a value for `(FOO 1)'
   Break loop
   1 lisp break> (plus2 1 1)      % We simply compute a value
   2                              % prints as 2
   2 lisp break> c                % continue with this value

   % it returns to compute "(foo 2)"

   ***** `FOO' is an undefined function {1001}
   ***** Continuation requires a value for `(FOO 2)'
   Break loop
   1 lisp break> 3                % again compute a value
   3
   2 lisp break> c                % and return
   5                              % finally complete

   % Pretend that we had really meant to call "fee":

   2> (de fee (x) (add1 x))
   FEE
   3> (plus2 (foo 1)(foo 2))             % now the bad expression
   ***** `FOO' is an undefined function {1001}
   ***** Continuation requires a value for `(FOO 1)'
   Break loop
   1 lisp break> e               % lets edit it

   Type HELP<CR> for a list of commands.

     edit> p                      % print form
   (FOO 1)
     edit> (1 fee)                % replace 1'st by "fee"
     edit> p                      % print again
   (FEE 1)
     edit> ok                     % we like it
   (FEE 1)
   2 lisp break> m               % show modified ErrorForm!*
   ErrorForm!* : `(FEE 1)'
   NIL
   3 lisp break> r               % Retry EVAL ErrorForm!*
   ***** `FOO' is an undefined function {1001}
   ***** Continuation requires a value for `(FOO 2)'
   Break loop
   1 lisp break> (de foo(x) (plus2 x 1))  % define foo
   FOO
   2 lisp break> r                        % and retry
   5
Error Handling and Recovery   7 February 1983                    PSL Manual
page 14.8                                                      section 14.4

14.4. Interrupt Keys
14.4. Interrupt Keys
14.4. Interrupt Keys

  Need to "LOAD INTERRUPT;" to enable.  This applies only to the DEC20.

  <Ctrl-T>  indicates  routine currently executing, gives the load average,
and gives the location counter in octal;

  <Ctrl-G> returns you to the Top-Loop;

  <Ctrl-B> takes you into a lower-level Break loop.



14.5. Details on the Break Loop
14.5. Details on the Break Loop
14.5. Details on the Break Loop

                                           Break                  Error
                                           Break                  Error
  If the SWITCH !*BREAK is T, the function Break() is called  by  Error  or
ContinuableError
ContinuableError
ContinuableError  before  unwinding  the  stacks,  or printing a backtrace.
                         Break
                         Break
Input and output to/from Break loops is done from/to the values  (channels)
of  BREAKIN!*  and  BREAKOUT!*.    The channels selected on entrance to the
Break
Break
Break loop are restored upon exit.


           __________                                                ______
BREAKIN!* [Initially: NIL]                                           global

        Rds
        Rds
     So Rds chooses STDIN!*.


            __________                                               ______
BREAKOUT!* [Initially: NIL]                                          global

     Similar to BREAKIN!*.

  Break                  Read-Eval-Print
  Break                  Read-Eval-Print
  Break is essentially a Read-Eval-Print  function,  called  in  the  error
context.    Any  FLUID  may  be  printed  or  changed, function definitions
                   Break                     TopLoop
                   Break                     TopLoop
changed, etc.  The Break  uses  the  normal  TopLoop  mechanism  (including
                         Catch                          TopLoop
                         Catch                          TopLoop
History),  embedded in a Catch with tag !$BREAK!$.  The TopLoop attempts to
use the parent loop's TOPLOOPREAD!*, TOPLOOPPRINT!* and TOPLOOPEVAL!*;  the
BreakEval
BreakEval                                 __
BreakEval function first checks top-level ids to see if they have a special
BREAKFUNCTION  on  their property lists, stored under 'BREAKFUNCTION.  This
is expected to be a function of no arguments, and  is  applied  instead  of
Eval
Eval
Eval.



14.6. Some Convenient Error Calls
14.6. Some Convenient Error Calls
14.6. Some Convenient Error Calls

  The following functions may be useful in user packages:


 FatalError
 FatalError _ ___   ____ ________                                      ____
(FatalError S:any): None Returned                                      expr
PSL Manual                    7 February 1983   Error Handling and Recovery
section 14.6                                                      page 14.9

        (ProgN (ErrorPrintF "***** Fatal error: %s" S)
               (While T Quit))


 RangeError
 RangeError ______ ___  _____ _______  __ ________   ____ ________     ____
(RangeError Object:any  Index:integer  Fn:function): None Returned     expr

        (StdError (BldMsg "Index %r out of range for %p in %p"
                                    Index  Object  Fn))


 StdError
 StdError _______ ______   ____ ________                               ____
(StdError Message:string): None Returned                               expr

        (Error 99 Message)


 TypeError
 TypeError ________ ___  __ ________  ___ ___   ____ ________          ____
(TypeError Offender:any  Fn:function  Typ:any): None Returned          expr

        (StdError (BldMsg "An attempt was made to do %p on %r,
                     which is not %w"   Fn  Offender  Typ))


 UsageTypeError
 UsageTypeError ___ ___ __ ________ ___ ___ _____ ___   ____ ________  ____
(UsageTypeError Off:any Fn:function Typ:any Usage:any): None Returned  expr

        (StdError
              (BldMsg "An attempt was made to use %r as %w in %p,
                   where %w is needed" Offender  Usage  Fn  Typ))


 IndexError
 IndexError ________ ___  __ ________   ____ ________                  ____
(IndexError Offender:any  Fn:function): None Returned                  expr

        (UsageTypeError Offender Fn "an integer" "an index")


 NonPairError
 NonPairError ________ ___  __ ________   ____ ________                ____
(NonPairError Offender:any  Fn:function): None Returned                expr

        (TypeError Offender Fn "a pair")


 NonIDError
 NonIDError ________ ___  __ ________   ____ ________                  ____
(NonIDError Offender:any  Fn:function): None Returned                  expr

        (TypeError Offender Fn "an identifier")


 NonNumberError
 NonNumberError ________ ___  __ ________   ____ ________              ____
(NonNumberError Offender:any  Fn:function): None Returned              expr

        (TypeError Offender Fn "a number")


 NonIntegerError
 NonIntegerError ________ ___  __ ________   ____ ________             ____
(NonIntegerError Offender:any  Fn:function): None Returned             expr
Error Handling and Recovery   7 February 1983                    PSL Manual
page 14.10                                                     section 14.6

        (TypeError Offender Fn "an integer")


 NonPositiveIntegerError
 NonPositiveIntegerError ________ ___  __ ________   ____ ________     ____
(NonPositiveIntegerError Offender:any  Fn:function): None Returned     expr

        (TypeError Offender Fn "a non-negative integer")


 NonCharacterError
 NonCharacterError ________ ___  __ ________   ____ ________           ____
(NonCharacterError Offender:any  Fn:function): None Returned           expr

        (TypeError Offender Fn "a character")


 NonStringError
 NonStringError ________ ___  __ ________   ____ ________              ____
(NonStringError Offender:any  Fn:function): None Returned              expr

        (TypeError Offender Fn "a string")


 NonVectorError
 NonVectorError ________ ___  __ ________   ____ ________              ____
(NonVectorError Offender:any  Fn:function): None Returned              expr

        (TypeError Offender Fn "a vector")


 NonSequenceError
 NonSequenceError ________ ___  __ ________   ____ ________            ____
(NonSequenceError Offender:any  Fn:function): None Returned            expr

        (TypeError Offender Fn "a sequence")



14.7. Special Purpose Error Handlers
14.7. Special Purpose Error Handlers
14.7. Special Purpose Error Handlers

  [???  This  needs  to  be  rethought  and reimplemented.  Currently not
  [???  This  needs  to  be  rethought  and reimplemented.  Currently not
  [???  This  needs  to  be  rethought  and reimplemented.  Currently not
  installed. ???]
  installed. ???]
  installed. ???]

  It  is  possible  to   handle   errors   specially.      The   value   of
                                                                   Error
                         _ ____                         ____       Error
ERRORHANDLERS!*  is  an  a-list of error number/handler pairs.  If Error is
                                                  Car
                                                  Car
called  with  a  number  which  appears  as  the  Car  of  an  element   of
                       Cdr
                       Cdr
ERRORHANDLERS!*,  its  Cdr  is taken to be a function of two variables, the
error number and the error message, which is called  instead.    If  called
      ContinuableError
      ContinuableError
from  ContinuableError with a non-NIL third argument, any value returned by
the  error  handler  is  returned  as  the  value  of  the  function  call.
                                                   Throw
                                                   Throw
Otherwise,  normal  termination  of  the  handler  Throws  to  the  closest
            ErrorSet
            ErrorSet
surrounding ErrorSet.
