{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}