;;; -*- Mode:gate; Fonts:(HL12 HL12I HL12B CPTFONTB HL12BI HL12B HL12I ) -*- =Node: Introduction =Text: 3INTRODUCTION* The first portion of this chapter explains how programs can handle errors, by means of condition handlers. It also explains how a program can signal an error if it detects something it doesn't like. The second explains how users can handle errors, by means of an interactive debugger; that is, it explains how to recover if you do something wrong. A new user of the Lisp Machine, or someone who just wants to know how to deal with errors and not how to cause them, should ignore the first sections and skip ahead to 4(DEBUGGING-4)The Debugger*. The remaining sections describe some other debugging facilities. Anyone who is going to be writing programs for the Lisp Machine should familiarize himself with these. The 1trace* facility provides the ability to perform certain actions at the time a function is called or at the time it returns. The actions may be simple typeout, or more sophisticated debugging functions. The 1advise* facility is a somewhat similar facility for modifying the behavior of a function. The 1breakon* facility allows you to cause the debugger to be entered when a certain function is called. You can then use the debugger's stepping commands to step to the next function call or return. The 1step* facility allows the evaluation of a form to be intercepted at every step so that the user may examine just what is happening throughout the execution of the form. Stepping works only on interpreted code. The 1MAR* facility provides the ability to cause a trap on any memory reference to a word (or a set of words) in memory. If something is getting clobbered by agents unknown, this can help track down the source of the clobberage. =Node: 4Conditions* =Text: 3CONDITIONS* Programmers often want to control what action is taken by their programs when errors or other exceptional situations occur. Usually different situations are handled in different ways, and in order to express what kind of handling each situation should have, each situation must have an associated name. In Zetalisp, noteworthy events are represented by objects called 1condition instances*. When an event occurs, a condition instance is created; it is then 1signaled*, and a 1handler* for that condition may be invoked. When a condition is signaled, the system (essentially) searches up the stack of nested function invocations looking for a handler established to handle that condition. The handler is a function that gets called to deal with the condition. The condition mechanism itself is just a convenient way for finding an appropriate handler function for a particular exceptional situation. When a condition is signaled, a 1condition instance* is created to represent the event and hold information about it. This information includes 1condition names* then classify the condition and any other data that is likely to be of interest to condition handlers. A condition instance is immutable once it has been created. Some conditions are 1errors*, which means that the debugger is invoked if they are signaled and not handled. Condition instances are flavor instances. The flavor 2condition* is the base flavor from which all flavors of condition are built. Several operations that are defined on condition instances are described below. The flavor 2error*, which is built on 2condition*, is the base flavor for all kinds of conditions which are errors. A 1condition name* is a symbol then is used to identify a category of conditions. Each condition instance possesses one or more condition names. Each condition handler specifies one or more condition names that it should apply to. A handler applies to a condition if they have any condition names in common. This is the sole purpose of condition names: to match condition instances with their handlers. The meaning of every condition name signaled by the system is described in this manual. The condition name index is a directory for them. Conditions that are errors possess the condition name 2error*. In PL/I, CLU, ADA and most other systems that provide named conditions, each condition has only one name. That is to say, the categories identified by condition names are disjoint. In Zetalisp, each condition instance can have multiple condition names, which means that the categories identified by condition names can overlap and be subdivided. For example, among the condition names defined by the system are 2condition*, 2error*, 2sys:arithmetic-error*, 2sys:floating-exponent-underflow* and 2sys:divide-by-zero*. 2condition* is a condition name that all condition instances possess. 2error* identifies the category of conditions that are considered errors. 2sys:arithmetic-error* identifies the category of errors that pertain to arithmetic operations. 2sys:floating-exponent-underflow* and 2sys:divide-by-zero* are the most specific level of categorization. So, the condition signaled when you evaluate 2(* 1s-30 1s-30 1s-30 1s-30)* possesses condition names 2sys:floating-exponent-underflow*, 2sys:arithmetic-error*, 2error* and 2condition*, while the one signaled if you evaluate 2(// 1 0)* possesses condition names 2sys:divide-by-zero*, 2sys:arithmetic-error*, 2error* and 2condition*. In this example, the categories fall into a strict hierarchy, but this does not need to be the case. Condition names are documented throughout the manual, with definitions like this: 3sys:divide-by-zero* (3sys:arithmetic-error* 3error*) 1Condition* The condition name 2sys:divide-by-zero* is always accompanied by 2sys:arithmetic-error* and 2error* (that is, it categorizes a subset of those categories). The presence of 2error* implies that all 2sys:divide-by-zero* conditions are errors. The condition instance also records additional information about the event. For example, the condition instance signaled by dividing by zero handles the 2:function* operation by returning the function that did the division (it might be 2truncate*, 2floor*, 2ceiling* or 2round*, as well as 2//*). In general, for each condition name there are conventions saying what additional information is provided and what operations to use to obtain it. The flavor of the condition instance is always one of the condition names, and so are its component flavors (with a few exceptions; 2si:vanilla-flavor* and some other flavor components are omitted, since they are not useful categories for condition handlers to specify). In our example, the flavor of the condition is 2sys:arithmetic-error*, and its components include 2error* and 2condition*. Condition names require new flavors only when they require significantly different handling by the error system; you will understand in detail after finishing this section. 3condition-typep* 1condition-instance* 1condition-name* Returns 2t* if 1condition-instance* possesses condition name 1condition-name*. 1condition-name* can also be a combination of condition names using 2and*, 2or* and 2not*; then the condition tested for is a boolean combination of the presence or absence of various condition names. Example: 3(condition-typep error 'fs:file-not-found)* 3(condition-typep error * 3 '(or fs:file-not-found fs:directory-not-found)) errorp* 1object* Returns 2t* if 1object* is a condition instance and its flavor incorporates 2error*. This is normally equivalent to 2(typep 1object* 'error)*. Some functions such as 2open* optionally return the condition instance rather than signaling it, if an error occurs. 2errorp* is useful in testing the value returned. 3:condition-names* 1Operation on 2condition** Returns a list of all the condition names possesses by this condition instance. =Node: 4Handling Conditions* =Text: 3HANDLING CONDITIONS* A condition handler is a function that is associated with certain condition names (categories of conditions). The variable 2eh:condition-handlers* contains a list of the handlers that are current; handlers are established using macros which bind this variable. When a condition is signaled, this list is scanned and all the handlers which apply are called, one by one, until one of the handlers either throws or returns non-2nil*. Since each new handler is pushed onto the front of 2eh:condition-handlers*, the innermost-established handler gets the first chance to handle the condition. When the handler is run, 2eh:condition-handlers* is bound so that the running handler (and all the ones that were established farther in) are not in effect. This avoids the danger of infinite recursion due to an error in a handler invoking the same handler. One thing a handler can do is throw to a tag. Often the 2catch* for this tag is right next to the place where the handler is established, but this does not have to be so. A simple handler that applies to all errors and just throws to a tag is established using 2ignore-errors*. 3ignore-errors* 1body...* 1Macro* An error within the execution of 1body* causes control to return from the 2ignore-errors* form. In this case, the values are 2nil*, 2t*. If there is no error inside 1body*, the first value is that of the last form in the 1body* and the second is 2nil*. Errors whose condition instances return true for the 2:dangerous-condition-p* operation are not handled. These include such things as running out of virtual memory. A handler can also signal another condition. For example, signaling 2sys:abort* has the effect of pretending that the user typed the 2Abort* key. The following function creates a handler which signals 2sys:abort*. 3si:eval-abort-trivial-errors* 1form* Evaluates 1form* with a condition handler for many common error conditions such as 2:wrong-type-argument*, 2:unbound-variable* and 2:unclaimed-message*. The handler asks the user whether to allow the debugger to be entered. If the user says `no', the handler signals the 2sys:abort* condition. If the user says `yes', the handler does not handle the condition, allowing the debugger to do so. In some cases the handler attempts to determine whether the incorrect variable, operation, or argument appeared in 1form*; if it did not, the debugger is always allowed to run. The assumption is that 1form* was typed in by the user, and the intention is to distinguish trivial mistakes from program bugs. The handler can also ask to proceed from the condition. This is done by returning a non-2nil* value. See the section on proceeding, 4(DEBUGGING-3)Proceeding*, for more information. The handler can also decline to handle the condition, by returning 2nil*. Then the next applicable handler is called, and so on until either some handler does handle the condition or there are no more handlers. The handler function is called in the environment where the condition was signaled, and in the same stack group. All special variables have the values they had at the place where the signaling was done, and all catch tags that were available at the point of signaling may be thrown to. The handler receives the condition instance as its first argument. When establishing the handler, you can also provide additional arguments to pass to the handler when it is called. This allows the same function to be used in varying circumstances. The fundamental means of establishing a condition handler is the macro 2condition-bind*. 3condition-bind* 1(handlers...)* 1body...* 1Macro* 3condition-bind-default* 1(handlers...)* 1body...* A 2condition-bind* form looks like this: 3(condition-bind ((1conditions* 1handler-form* 1additional-arg-forms*...)* 3 (1conditions* 1handler-form* 1additional-arg-forms*...))* 3 1body*...)* The purpose is to execute 1body* with one or more condition handlers established. Each list of conditions and handler-form establishes one handler. 1conditions* is a condition name or a list of condition names to which the handler should apply. It is 1not* evaluated. 1handler-form* is evaluated to produce the function that is the actual handler. The 1additional-arg-forms* are evaluated, on entry to the 2condition-bind*, to produce additional arguments that are passed to the handler function when it is called. The arguments to the handler function are the condition instance being signaled, followed by the values of any 1additional-arg-forms*. 1conditions* can be 2nil*; then the handler applies to all conditions that are signaled. In this case it is up to the handler function to decide whether to do anything. It is important for the handler to refrain from handling certain conditions that are used for debugging, such as 2break* and 2eh:call-trap*. The 2:debugging-condition-p* operation on condition instances returns non-2nil* for these conditions. Certain other conditions such as 2sys:virtual-memory-overflow* should be handled only with great care. The 2:dangerous-condition-p* operation returns non-2nil* for these conditions. Example: 3(condition-bind ((nil 'myhandler "it happened here" 45))* 3 (catch 'x* 3 ...))* 3(defun myhandler (condition string value)* 3 (unless (or (condition-typep condition 'fs:file-error)* 3 (send condition :dangerous-condition-p)* 3 (send condition :debugging-condition-p))* 3 (format error-output "~&~A:~%~A~%" string condition)* 3 (throw 'x value)))* 2myhandler* declines to handle file errors, and all debugging conditions and dangerous errors. For all other conditions, it prints the string specified in the condition bind and throws to the tag 2x* the value specified there (45). 2condition-bind-default* is like 2condition-bind* but establishes a 1default* 1handler* instead of an ordinary handler. Default handlers work like ordinary handlers, but they are tried in a different order: first all the applicable ordinary handlers are given a chance to handle the condition, and then the default handlers get their chance. A more flexible way of doing things like this is described under 2signal-condition* (4(DEBUGGING-2)Signaling a Condition Instance*). Condition handlers that simply throw to the function that established them are very common, so there are special constructs provided for defining them. 3condition-case* 1(variables...)* 1body-form* 1clauses...* 1Macro* 3(condition-case (1variable*)* 3 1body-form** 3 (1condition-names* 1forms*...)* 3 (1condition-names* 1forms*...)* 3 ...)* 1body-form* is executed with a condition handler established that will throw back to the 2condition-case* if any of the specified condition names is signaled. Each list starting with some condition names is a 1clause*, and specifies what to do if one of those condition names is signaled. 1condition-names* is either a condition name or a list of condition names; it is not evaluated. Once the handler per se has done the throw, the clauses are tested in order until one is found that applies. This is almost like a 2selectq*, except that the signaled condition can have several condition names, so the first clause that matches any of them gets to run. The forms in the clause are executed with 1variable* bound to the condition instance that was signaled. The values of the last form in the clause are returned from the 2condition-case* form. If none of the specified conditions is signaled during the execution of 1body-form* (or if other handlers, established within 1body-form*, handle them) then the values of 1body-form* are returned from the 2condition-case* form. 1variable* may be omitted if it is not used. It is also possible to have a clause starting with 2:no-error* in place of a condition name. This clause is executed if 1body-form* finishes normally. Instead of just one 1variable* there can be several variables; during the execution of the 2:no-error* clause, these are bound to the values returned by 1body-form*. The values of the last form in the clause become the values of the 2condition-case* form. Here is an example: 3(condition-case ()* 3 (print foo)* 3 (error (format t " <>"))) condition-call* 1(variables...)* 1body-form* 1clauses...* 1Macro* 2condition-call* is an extension of 2condition-case* that allows you to give each clause an arbitrary conditional expression instead of just a list of condition names. It looks like this: 3(condition-call (1variables*...)* 3 1body-form** 3 (1test* 1forms*...)* 3 (1test* 1forms*...)* 3 ...)* The difference between this and 2condition-case* is the 1test* in each clause. The clauses in a 2condition-call* resemble the clauses of a 2cond* rather than those of a 2selectq*. When a condition is signaled, each 1test* is executed while still within the environment of the signaling (that is, within the actual handler function). The condition instance can be found in the first 1variable*. If any 1test* returns non-2nil*, then the handler throws to the 2condition-call* and the corresponding clause's 1forms* are executed. If every 1test* returns 2nil*, the condition is not handled by this handler. In fact, each 1test* is computed a second time after the throw has occurred in order to decide which clause to execute. The code for the 1test* is copied in two different places, once into the handler function to decide whether to throw, and once in a 2cond* which follows the catch. The last clause can be a 2:no-error* clause just as in 2condition-case*. It is executed if the body returns without error. The values returned by the body are stored in the 1variables*. The values of the last form in the 2:no-error* clause are returned by the 2condition-call*. Only the first of 1variables* is used if there is no 2:no-error* clause. The 1variables* may be omitted entirely in the unlikely event that none is used. Example: 3(condition-call (instance)* 3 (do-it)* 3 ((condition-typep instance* 3 '(and fs:file-error (not fs:no-more-room)))* 3 (compute-what-to-return)))* The condition name 2fs:no-more-room* is a subcategory of 2fs:file-error*; therefore, this handles all file errors 1except* for 2fs:no-more-room*. Each of the four condition handler establishing constructs has a conditional version that decides at run time whether to establish the handlers. 3condition-bind-if* 1cond-form* 1(handlers...)* 1body...* 1Macro* 3(condition-bind-if 1cond-form** 3 ((1conditions* 1handler-form* 1additional-arg-forms*...)* 3 (1conditions* 1handler-form* 1additional-arg-forms*...))* 3 1body*...)* begins by executing 1cond-form*. If it returns non-2nil*, then all proceeds as for a regular 2condition-bind*. If 1cond-form* returns 2nil*, then the 1body* is still executed but without the condition handler. 3condition-case-if* 1cond-form* 1(variables...)* 1body-form* 1clauses...* 1Macro* 3(condition-case-if 1cond-form* (1variables*...)* 3 1body-form** 3 (1condition-names* 1forms*...)* 3 (1condition-names* 1forms*...)* 3 ...)* begins by executing 1cond-form*. If it returns non-2nil*, then all proceeds as for a regular 2condition-case*. If 1cond-form* returns 2nil*, then the 1body-form* is still executed but without the condition handler. 1body-form*'s values are returned, or, if there is a 2:no-error* clause, it is executed and its values returned. 3condition-call-if* 1cond-form* 1([variable])* 1body-form* 1clauses...* 1Macro* 3(condition-call-if 1cond-form* (1variables*...)* 3 1body-form** 3 (1test* 1forms*...)* 3 (1test* 1forms*...)* 3 ...)* begins by executing 1cond-form*. If it returns non-2nil*, then everything proceeds as for a regular 2condition-call*. If 1cond-form* returns 2nil*, then the 1body-form* is still executed but without the condition handler. In that case, 1body-form*'s values are returned, or, if there is a 2:no-error* clause, it is executed and its values returned. 3condition-bind-default-if* 1cond-form* 1(handlers...)* 1body...* 1Macro* This is used just like 2condition-bind-if*, but establishes a default handler instead of an ordinary handler. 3eh:condition-handlers* 1Variable* This is the list of established condition handlers. Each element looks like this: 3(1condition-names* 1function* 1additional-arg-values*...)* 1condition-names* is a condition name or a list of condition names, or 2nil* which means all conditions. 1function* is the actual handler function. 1additional-arg-values* are additional arguments to be passed to the 1function* when it is called. 1function*'s first argument is always the condition instance. Both the links of the value of 2eh:condition-handlers* and the elements are usually created with 2with-stack-list*, so copy them if you want to save them for any period of time. 3eh:condition-default-handlers* 1Variable* This is the list of established default condition handlers. The data format is the same as that of 2eh:condition-handlers*. =Node: 4Standard Condition Flavors* =Text: 3STANDARD CONDITION FLAVORS condition* 1Flavor* The flavor 2condition* is the base flavor of all conditions, and provides default definitions for all the operations described in this chapter. 2condition* incorporates 2si:property-list-mixin*, which defines operations 2:get* and 2:plist*. Each property name on the property list is also an operation name, so that sending the 2:foo* message is equivalent to 2(send instance :get :foo)*. In addition, 2(send instance :set :foo* 1value2)** is equivalent to 2(send instance :set :get :foo 1value*)*. 2condition* also provides two instance variables, 2eh:format-string* and 2eh:format-args*. 2condition*'s method for the the 2:report* operation passes these to 2format* to print the error message. 3error* 1Flavor* The flavor 2error* makes a condition an error condition. 2errorp* returns 2t* for such conditions, and the debugger is entered if they are signaled and not otherwise handled. 3sys:no-action-mixin* 1Flavor* This mixin provides a definition of the proceed type 2:no-action*. 3sys:proceed-with-value-mixin* 1Flavor* This mixin provides a definition of the proceed type 2:new-value*. 3ferror* 1Flavor* This flavor is a mixture of 2error*, 2sys:no-action-mixin* and 2sys:proceed-with-value-mixin*. It is the flavor used by default by the functions 2ferror* and 2cerror*, and is often convenient for users to instantiate. 3sys:warning* 1Flavor* This flavor is a mixture of 2sys:no-action-mixin* and 2condition*. 3sys:bad-array-mixin* 1Flavor* This mixin provides a definition of the proceed type 2:new-array*.