{Begin SubSec Unbound Atoms and Undefined Functions}
{Title Unbound Atoms and Undefined Functions}
{Text


Whenever the interpreter evaluates an atom with no binding on the stack, and whose top level value is the atom {atom NOBIND}{index *PRIMARY* NOBIND}, the interpreter calls the function {index *PRIMARY* FAULTEVAL}{fn FAULTEVAL}.  Similarly, {fn FAULTEVAL} is called when a list is encountered, {fn CAR} of which is not the name of a function or a {index function objects}function object.{foot
In Interlisp-10,{note -D?} because of the widespread use of CLISP ({SectionRef L!CLISP}), before calling {fn FAULTEVAL}, if {var CLISPARRAY} is non-{lisp NIL},  the interpreter performs {lisp (GETHASH {arg EXPRESSION} CLISPARRAY)}, and if the result is non-{lisp NIL}, treats it as the new expression to be evaluated, and goes on.  This avoids going through the {fn FAULTEVAL} mechanism, and is done purely in the interests of efficiency.
}{comment endfootnote}
The value returned by {fn FAULTEVAL} is used by the interpreter exactly as though it were the value of the form.


{fn FAULTEVAL} is defined to print either {lisp U.B.A.}{index *PRIMARY* U.B.A. EM} (for {lisp U}n{lisp B}ound {lisp A}tom){index *PRIMARY* unbound atom} or {lisp U.D.F.}{index *PRIMARY* U.D.F. EM} (for {lisp U}n{lisp D}efined {lisp F}unction){index *PRIMARY* undefined function} and then to call {fn BREAK1} giving it the offending form as {index BRKEXP  BV}{arg BRKEXP}.

If DWIM{index DWIM} is enabled (and a break is going to occur), {fn FAULTEVAL} also prints the offending form (in the case of a {lisp U.B.A.}, the parent form) and the name of the function which contains the form.
For example, if {lisp FOO} contains {lisp (CONS X FIE)} and {lisp FIE} is unbound, {fn FAULTEVAL} prints:
{lisp U.B.A. FIE [in FOO] in (CONS X FIE)}.
Note that if DWIM is not enabled, the user can obtain this information after he is inside the break via the {index IN? BC} {breakcom IN?} command.

Once inside the break, the user can set the atom, define the function, return a specified value for the form using the {breakcom RETURN} command, etc., or abort the break using the {breakcom ↑} command.
If the break is exited with a value,{index value of a break} the computation
will proceed exactly as though no error had occurred.

A similar procedure is followed whenever {index APPLY}{fn APPLY} or {index APPLY*}{fn APPLY*} are called with an undefined function, i.e., one
whose {fn FNTYP} is {lisp NIL}.
In this case, {index *PRIMARY* FAULTAPPLY}{fn FAULTAPPLY} is called giving it the function as its first argument and the list of arguments to the
function as its second argument.
The value returned by {fn FAULTAPPLY} is used as the value of {fn APPLY} or {fn APPLY*}.
{fn FAULTAPPLY} is defined to print {lisp U.D.F.}{index U.D.F. EM} and then call {index BREAK1}{fn BREAK1} giving it
{lisp (APPLY (QUOTE {arg FN}) (QUOTE {arg ARGS}))} as {index BRKEXP  BV}{arg BRKEXP}.  Once inside the break, the user can define the function, return a specified value, etc.  If the break is exited with a value,{index value of a break} the computation will proceed exactly as though no error had occurred.  {fn FAULTAPPLY} is also called for undefined function calls from compiled code.



{Begin Note}
Date: 29 SEP 1982 2012-PDT
From: JONL.PA
Subject: Undefined Function

Once in a while, I mistype a DEFINEQ, and wind up with an s-expression in the definition cell of some litatom which is *almost* what I wanted -- it just lacks the word LAMBDA.  The error message you get when you try to run such a function is "Undefined Function" -- wouldn't it be better to reserve that msg for the case of a definition cell which is either NIL or NOBIND, and print something more informative for the case where it contains something like ((X) (LIST X (TIMES 2 X)), or (() (PRINT 5)).
{End Note}


}{End SubSec Unbound Atoms and Undefined Functions}


{Begin SubSec Other Types of Errors}
{Title Other Types of Errors}
{Text

In addition to {lisp U.B.A.}{index U.B.A. EM} and {lisp U.D.F.}{index U.D.F. EM} errors, there are currently 28 {Note How many now?} other error types in Interlisp, e.g., {lisp P-STACK OVERFLOW}, {lisp NON-NUMERIC ARG}, {lisp FILE NOT OPEN}, etc.
A complete list is given later in this section.
When an error occurs, the decision about whether or not to break is handled by {index BREAKCHECK}{fn BREAKCHECK} and is the same as with {lisp U.B.A.}
and {lisp U.D.F.} errors.
If a break is to occur, the exact action that follows depends on the type of error.


{note following doesn't work in Interlisp-D}

For example, if a break is to occur following evaluation of {lisp (RPLACA NIL (ADD1 5))} (which causes an {lisp ATTEMPT TO RPLAC NIL} error),
the message printed will be {lisp (RPLACA BROKEN)}, {index BRKEXP  BV}{arg BRKEXP} will be {lisp (RPLACA U V W)}, {lisp U} will be bound to {lisp NIL,} {lisp V} to 6, and {lisp W} to {lisp NIL}, and the stack will look like the user had broken on {fn RPLACA} himself.
Following a {lisp NON-NUMERIC ARG}{index NON-NUMERIC ARG EM} error, the system will type {index IN  TY}{lisp IN} followed by the name of the most recently entered function, and then {lisp (BROKEN)}.{index (BROKEN) TY}
The system will then effectively be in a break {it inside} of this function.
{index BRKEXP  BV}{arg BRKEXP} will be a call to {fn ERROR} so that if the user types {index OK  BC}{breakcom OK} or {index EVAL  BC}{breakcom EVAL} or {index GO  BC}{breakcom GO}, a {index ?  TY}{lisp ?} will be printed and the break maintained.
However, if the break is exited with a value via the {index RETURN  BC}{breakcom RETURN} command,{foot 
Presumably the value will be a number, or the error will occur again.
}{comment endfootnote}
the computation will proceed exactly as though no error had occurred.

}{End SubSec Other Types of Errors}