;;; -*- Mode:gate; Fonts:(HL12 HL12I HL12B CPTFONTB HL12BI HL12B HL12I ) -*- =Node: 4Condition Operations* =Text: 3CONDITION OPERATIONS* Every condition instance can be asked to print an 1error message* which describes the circumstances that led to the signaling of the condition. The easiest way to print one is to print the condition instance without escaping (2princ*, or 2format* operation 2~A*). This actually uses the 2:report* operation, which implements the printing of an error message. When a condition instance is printed with escaping, it uses the 2#* syntax so that it can be read back in. This is done using 2si:print-readably-mixin*, 4(FLAVOR-5)Printing Flavor Instances Readably*. 3:report* 1stream* 1Operation on 2condition** Prints on 1stream* the condition's error message, a description of the circumstances for which the condition instance was signaled. The output should neither start nor end with a carriage return. If you are defining a new flavor of condition and wish to change the way the error message is printed, this is the operation to redefine. All others use this one. 3:report-string* 1Operation on 2condition** Returns a string containing the text that the 2:report* operation would print. Operations provided specifically for condition handlers to use: 3:dangerous-condition-p* 1Operation on 2condition** Returns 2t* if the condition instance is one of those that indicate events that are considered extremely dangerous, such as running out of memory. Handlers that normally handle all conditions might want to make an exception for these. 3:debugging-condition-p* 1Operation on 2condition** Returns 2t* if the condition instance is one of those that are signaled as part of debugging, such as 2break*, which is signaled when you type 2Meta-Break*. Although these conditions normally enter the debugger, they are not errors; this serves to prevent most condition handlers from handling them. But any condition handler which is written to handle 1all* conditions should probably make a specific exception for these. See also the operations 2:proceed-types* and 2:proceed-type-p*, which have to do with proceeding (4(DEBUGGING-3)Proceeding*). =Node: 4Condition Operations for the Debugger* =Text: 3CONDITION OPERATIONS FOR THE DEBUGGER* Some operations are intended for the debugger to use. They are documented because some flavors of condition redefine them so as to cause the debugger to behave differently. This section is of interest only to advanced users. 3:print-error-message* 1stack-group* 1brief-flag* 1stream* 1Operation on 2condition** This operation is used by the debugger to print a complete error message. This is done primarily using the 2:report* operation. Certain flavors of condition define a 2:after* 2:print-error-message* method which, when 1brief-flag* is 2nil*, prints additional helpful information which is not part of the error message per se. Often this requires access to the stack group in addition to the data in the condition instance. The method can assume that if 1brief-flag* is 2nil* then 1stack-group* is not the one which is executing. For example, the 2:print-error-message* method of the condition signaled when you call an undefined function checks for the case of calling a function such as 2bind* that is meaningful only in compiled code; if that is what happened, it searches the stack to look for the name of the function in which the call appears. This is information that is not considered crucial to the error itself, and is therefore not recorded in the condition instance. 3:maybe-clear-input* 1stream* 1Operation on 2condition** This operation is used on entry to the debugger to discard input. Certain condition flavors, used by stepping redefine this operation to do nothing, so that input is not discarded. 3:bug-report-recipient-system* 1Operation on 2condition** The value returned by this operation is used to determine what address to mail bug reports to, when the debugger 2Control-M* command is used. By default, it returns 2"LISPM"*. The value is passed to the function 2bug*. 3:bug-report-description* 1stream* &optional 1numeric-arg* 1Operation on 2condition** This operation is used by the 2Control-M* command to print on 1stream* the information that should go in the bug report. 1numeric-arg* is the numeric argument, if any, that the user gave to the 2Control-M* command. 3:find-current-frame* 1stack-group* 1Operation on 2condition** Returns the stack indices of the stack frames that the debugger should operate on. The first value is the frame ``at which the error occurred.'' This is not the innermost stack frame; it is outside the calls to such functions as 2ferror* and 2signal-condition* which were used to signal the error. The second value is the initial value for the debugger command loop's current frame. The third value is the innermost frame that the debugger should be willing to let the user see. By default this is the innermost active frame, but it is safe to use an open but not active frame within it. The fourth value, if non-2nil*, tells the debugger to consider the innermost frame to be ``interesting''. Normally, frames that are part of the interpreter (calls to 2si:eval1*, 2si:apply-lambda*, 2prog*, 2cond*, etc.) are considered uninteresting. This is a flavor operation so that certain flavors of condition can redefine it. 3:debugger-command-loop* 1stack-group* &optional 1error-object* 1Operation on 2condition** Enters the debugger command loop. The initial error message and backtrace have already been printed. This message is sent in an error handler stack group; 1stack-group* is the stack group in which the condition was signaled. 1error-object* is the condition object which was signaled; it defaults to the one the message is sent to. This operation uses 2:or* method combination (see 4(FLAVOR-4)Method Combination*). Some condition flavors add methods that perform some other sort of processing or enter a different command loop. For example, unbound variable errors look for look-alike symbols in other packages at this point. If the added method returns 2nil*, the original method that enters the usual debugger command loop is called. =Node: 4Signaling Conditions* =Text: 3SIGNALING CONDITIONS* Signaling a condition has two steps, creating a condition instance and signaling the instance. There are convenience interface functions that combine the two steps. You can also do them separately. If you just want to signal an error and do not want to worry much about condition handling, the function 2ferror* is all you need to know. =Node: 4Convenience Functions for Signaling* =Text: 3CONVENIENCE FUNCTIONS FOR SIGNALING ferror* &rest 1make-condition-arguments* Creates a condition instance using 2make-condition* and then signals it with 2signal-condition*, specifying no local proceed types, and with 2t* as the 1use-debugger* argument so the debugger is always entered if the condition is not otherwise handled. The first argument to 2ferror* is always a signal name (often 2nil*). The second argument is usually a format string and the remaining arguments are additional arguments for 2format*; but this is under the control of the definition of the signal name. Example: 3(ferror 'math:singular-matrix* 3 "The matrix ~S cannot be inverted." matrix)* For compatibility with the Symbolics system, if the first argument to 2ferror* is a string, then a signal name of 2nil* is assumed. The arguments to 2ferror* are passed on to 2make-condition* with an additional 2nil* preceding them. If you prefer, you can use the formatted output functions (4(IOSYSTEM-3)The Output Subsystem*) to generate the error message. Here is an example, though in a simple case like this using 2format* is easier: 3(ferror 'math:singular-matrix* 3 (format:outfmt* 3 "The matrix "* 3 (prin1 matrix)* 3 " cannot be inverted.")* 3 number)* In this case, arguments past the second one are not used for printing the error message, but the signal name may still expect them to be present so it can put them in the condition instance. 3cerror* 1proceed-type* 1ignore* 1signal-name* &rest 1signal-name-arguments* Creates a condition instance, by passing the 1signal-name* and 1signal-name-arguments* to 2make-condition*, and then signals it. If 1proceed-type* is non-2nil* then it is provided to 2signal-condition* as a proceed type. For compatibility with old uses of 2cerror*, if 1proceed-type* is 2t*, 2:new-value* is provided as the proceed type. If 1proceed-type* is 2:yes*, 2:no-action* is provided as the proceed type. The second argument to 2cerror* is not used and is present for historical compatibility. It may be given a new meaning in the future. If a condition handler or the debugger decides to proceed, the second value it returns becomes the value of 2cerror*. Common Lisp defines another calling sequence for this function: 3(cerror 1continue-format-string* 1error-format-string* 1args*...)* This signals an error of flavor 2eh:common-lisp-cerror*, which prints an error message using 1error-format-string* and 1args*. It allows one proceed type, whose documentation is 1continue-format-string*, and which proceeds silently, returning 2nil* from 2cerror*. 2cerror* can tell which calling sequence has been used and behaves accordingly. 3warn* 1format-string* &rest 1args* Prints a warning on 2*error-output** by passing the args to 2format*, starting on a fresh line, and then returns. If 2*break-on-warnings** is non-2nil*, however, 2warn* signals a procedable error, using the arguments to make an error message. If the user proceeds, 2warn* simply returns. 3*break-on-warnings** If non-2nil*, 2warn* signals an error rather than just printing a message. 3check-type* 1place* 1type-spec* 1[description]* 1Macro* 3check-arg-type* 1place* 1type-spec* 1[description]* Signals a correctable error if the value of 1place* does not fit the type 1type-spec*. 1place* is something that 2setf* can store in. 1type-spec* is a type specifier, a suitable second argument to 2typep*, and is not evaluated (see 4(PRIMOBJTYPE-0)Primitive Object Types*). A simple example is: 3(check-type foo (integer 0 10))* This signals an error unless 2(typep foo '(integer 0 10))*; that is, unless 2foo*'s value is an integer between zero and ten, inclusive. If an error is signaled, the error message contains the name of the variable or place where the erroneous value was found, and the erroneous value itself. An English description of the type of object that was wanted is computed automatically from the type specifier for use in the error message. For the commonly used type specifiers this computed description is adequate. If it is unsatisfactory in a particular case, you can specify 1description*, which is used instead. In order to make the error message grammatical, 1description* should start with an indefinite article. The error signaled is of condition 2sys:wrong-type-argument* (see 4(EVAL-4)Evaluation and Function Calling Errors*). The proceed type 2:argument-value* is provided. If a handler proceeds using this proceed type, it should specify one additional argument; that value is stored into 1place* with 2setf*. The new value is then tested, and so on. 2check-type* returns when a value passes the test. 2check-arg-type* is an older name for this macro. 3check-arg* 1var-name* 1predicate* 1description* 1[type-symbol]* 1Macro* 2check-arg* is an obsolete variant of 2check-type*. 1predicate* is either a symbol which is predicate (a function of one argument) or a list which is a form. If it is a predicate, it is applied to the value of 1var-name*, which is valid if the predicate returns non-2nil*. If it is a form, it is evaluated, and the value is valid of the form returns non-2nil*. The form ought to make use of 1var-name*, but nothing checks this. There is no way to compute an English description of valid values from 1predicate*, so a 1description* string must always be supplied. 1type-symbol* is a symbol that is used by condition handlers to determine what type of argument was expected. If 1predicate* is a symbol, you may omit 1type-symbol*, and 1predicate* is used for that purpose as well. The use of the 1type-symbol* is not really well-defined, and 2check-type*, where a type specifier serves both purposes, is superior to 2check-arg* for this reason. Examples: 3(check-arg foo stringp "a string")* 3(check-arg h* 3 (or (stringp h) (typep h 'fs:host))* 3 "a host name"* 3 fs:host)* Other functions that can be used to test for invalid values include 2ecase* and 2ccase* (4(FLOWCTL-1)Conditionals*), which are error-checking versions of 2selectq*, and 2etypecase* and 2ctypecase* (4(PRIMOBJTYPE-1)Testing Types with Type Specifiers*), error-checking versions of 2typecase*. 3assert* 2test-form* 1[(2places*...)* 1[2string** 2args1...]]** 1Macro* Signals an error if 1test-form* evaluates to 2nil*. The rest of the 2assert* form is relevant only if the error happens. First of all, the 1places* are forms that can be stored into with 2setf*, and which are used (presumably) in 1test-form*. The reason that the 1places* are specified again in the 2assert* is so that the expanded code can arrange for the user to be able to specify a new value to be stored into any one of them when he proceeds from the error. When the error is signaled, one proceed-type is provided for each 1place* that is given. The condition object has flavor 2eh:failed-assertion*. If the user does proceed with a new value in that fashion, the 1test-form* is evaluated again, and the error repeats until the 1test-form* comes out non-2nil*. The 1string* and 1args* are used to print the error message. If they are omitted, 2"Failed* 2assertion"* is used. They are evaluated only when an error is signaled, and are evaluated again each time an error is signaled. 2setf*'ing the 1places* may also involve evaluation, which happens each time the user proceeds and sets one. Example: 3(assert (neq (car a) (car b)) ((car a) (car b))* 3 "The CARS of A and B are EQ: ~S and ~S" * 3 (car a) (car b))* The 1places* here are 2(car a)* and 2(car b)*. The 1args* happen to be the same two forms, by not-exactly-coincidence; the current values of the 1places* are often useful in the error message. The remaining signaling functions are provided for compatibility only. 3error* &rest 1make-condition-arguments* 2error* exists for compatibility with Maclisp and the Symbolics version of Zetalisp. It takes arguments in three patterns: 3(error 1string* 1object* [1interrupt*])* which is used in Maclisp, and 3(error 1condition-instance*)* 3(error 1flavor-name* 1init-options*...)* which are used by Symbolics. (In fact, the arguments to 2error* are simply passed along to 2make-condition* if they do not appear to fit the Maclisp pattern). If the Maclisp argument pattern is not used then there is no difference between 2error* and 2ferror*. 3cli:error* 2format-string* &rest 2args* The Common Lisp version of 2error* signals an uncorrectable error whose error message is printed by passing 1format-string* and 1args* to 2format*. 3fsignal* 1format-string* &rest 1format-args* This function is for Symbolics compatibility only, and is equivalent to 3(cerror :no-action nil nil 1format-string* 1format-args*...) signal* 1signal-name* &rest 1remaining-make-condition-arguments* The 1signal-name* and 1remaining-make-condition-arguments* are passed to 2make-condition*, and the result is signaled with 2signal-condition*. If the 1remaining-make-condition-arguments* are keyword arguments and 2:proceed-types* is one of the keywords, the associated value is used as the list of proceed types. In particular, if 1signal-name* is actually a condition instance, so that the remaining arguments will be ignored by 2make-condition*, it works to specify the proceed types this way. If the proceed types are not specified, a list of all the proceed types that the condition instance knows how to prompt the user about is used by default. 3errset* 1form* 1[flag]* 1Macro* Catches errors during the evaluation of 1form*. If an error occurs, the usual error message is printed unless 1flag* is 2nil*. Then control is thrown and the errset-form returns 2nil*. 1flag* is evaluated first and is optional, defaulting to 2t*. If no error occurs, the value of the errset-form is a list of one element, the value of 1form*. 2errset* is an old, Maclisp construct, implemented much like 2condition-case*. Many uses of 2errset* or 2errset*-like constructs really ought to be checking for more specific conditions instead. 3catch-error* 1form* 1[flag]* 1Macro* 2catch-error* is a variant of 2errset*. This construct catches errors during the evaluation of 1form* and returns two values. If 1form* returns normally, the first value is 1form*'s first value and the second value is 2nil*. If an error occurs, the usual error message is printed unless 1flag* is 2nil*, and then control is thrown out of the 2catch-error* form, which returns two values, first 2nil* and second a non-2nil* value that indicates the occurrence of an error. 1flag* is evaluated before 1form* and is optional, defaulting to 2t*. 3errset* 1Variable* If this variable is non-2nil*, 2errset* forms are not allowed to trap errors. The debugger is entered just as if there were no 2errset*. This is intended mainly for debugging. The initial value of 2errset* is 2nil*. 3err* 1Macro* This is for Maclisp compatibility only and should not be used. 2(err)* is a dumb way to cause an error. If executed inside an 2errset*, that 2errset* returns 2nil*, and no message is printed. Otherwise an error is signaled with error message just 2"ERROR>>"*. 2(err 1form*)* evaluates 1form* and causes the containing 2errset* to return the result. If executed when not inside an 2errset*, an error is signaled with 1form*'s value printed as the error message. 2(err 1form* 1flag*)*, which exists in Maclisp, is not supported. =Node: 4Creating Condition Instances* =Text: 3CREATING CONDITION INSTANCES* You can create a condition instance quite satisfactorily with 2make-instance* if you know which instance variables to initialize. For example, 3(make-instance 'ferror :condition-names '(foo)* 3 :format-string "~S loses."* 3 :format-args losing-object)* creates an instance of 2ferror* just like the one that would be signaled if you do 3(ferror 'foo "~S loses." losing-object)* Note that the flavor name and its components' names are added in automatically to whatever you specify for the 2:condition-names* keyword. Direct use of 2make-instance* is cumbersome, however, and it is usually handier to define a 1signal name* with 2defsignal* or 2defsignal-explicit* and then create the instance with 2make-condition*. A signal name is a sort of abbreviation for all the things that are always the same for a certain sort of condition: the flavor to use, the condition names, and what arguments are expected. In addition, it allows you to use a positional syntax for the arguments, which is usually more convenient than a keyword syntax in simple use. Here is a typical 2defsignal*: 3(defsignal series-not-convergent sys:arithmetic-error (series)* 3 "Signaled by limit extractor when SERIES does not converge.")* This defines a signal name 2series-not-convergent*, together with the name of the flavor to use (2sys:arithmetic-error*, whose meaning is being stretched a little), an interpretation for the arguments (2series*, which is explained below), and a documentation string. The documentation string is not used in printing the error message; it is documentation for the signal name. It becomes accessible via 2(documentation 'series-not-convergent 'signal)*. 2series-not-convergent* could then be used to signal an error, or just to create a condition instance: 3(ferror 'series-not-convergent* 3 "The series ~S went to infinity." myseries)* 3(make-condition 'series-not-convergent* 3 "The series ~S went to infinity." myseries)* The list 2(series)* in the 2defsignal* is a list of implicit instance variable names. They are matched against arguments to 2make-condition* following the format string, and each implicit instance variable name becomes an operation defined on the condition instance to return the corresponding argument. (You can imagine that 2:gettable-instance-variables* is in effect for all the implicit instance variables.) In this example, sending a 2:series* message to the condition instance returns the value specified via 2myseries* when the condition was signaled. The implicit instance variables are actually implemented using the condition instance's property list. Thus, 2defsignal* spares you the need to create a new flavor merely in order to remember a particular datum about the condition. 3defsignal* 1signal-name* 1(flavor* 1condition-names...)* 1implicit-instance-variables* 1documentation* 1extra-init-keyword-formsMacro* Defines 1signal-name* to create an instance of 1flavor* with condition names 1condition-names*, and implicit instance variable whose names are taken from the list 1implicit-instance-variables* and whose values are taken from the 2make-condition* arguments following the format string. Instead of a list 2(1flavor** 1condition-names2...)** there may appear just a flavor name. This is equivalent to using 1signal-name* as the sole condition name. The1 extra-init-keyword-forms* are forms to be evaluated to produce additional keyword arguments to pass to 2make-instance*. These can be used to initialize other instance variables that particular flavors may have. These expressions can refer to the 1implicit-instance-variables*. 1documentation* is a string which is recorded so that it can be accessed via the function 2documentation*, as in 2(documentation 1signal-name* 'signal)*. 3defsignal-explicit* 1signal-name* 1(flavor* 1condition-names...)* 1signal-arglist* 1documentation* 1init-keyword-forms...Macro* Like 2defsignal*, 2defsignal-explicit* defines a signal name. This signal name is used the same way, but the way it goes about creating the condition instance is different. First of all, there is no list of implicit instance variables. Instead, 1signal-arglist* is a lambda list which is matched up against all the arguments to 2make-condition* except for the signal-name itself. The variables bound by the lambda list can be used in the 1init-keyword-forms*, which are evaluated to get arguments to pass to 2make-instance*. For example: 3(defsignal-explicit mysignal-3 * 3 (my-error-flavor mysignal-3 my-signals-category)* 3 (format-string losing-object &rest format-args)* 3 "The third kind of thing I like to signal."* 3 :format-string format-string* 3 :format-args (cons losing-object (copylist format-args))* 3 :losing-object-name (send losing-object :name))* Since implicit instance variables are really just properties on the property list of the instance, you can create them by using init keyword 2:property-list*. The contents of the property list determines what implicit instance variables exist and their values. 3make-condition* 1signal-name* &rest 1arguments* 2make-condition* is the fundamental way that condition instances are created. The 1signal-name* says how to interpret the 1arguments* and come up with a flavor and values for its instance variables. The handling of the 1arguments* is entirely determined by the 1signal-name*. If 1signal-name* is a condition instance, 2make-condition* returns it. It is not useful to call 2make-condition* this way explicitly, but this allows condition instances to be passed to the convenience functions 2error* and 2signal* which call 2make-condition*. If the 1signal-name* was defined with 2defsignal* or 2defsignal-explicit*, then that definition specifies exactly how to interpret the 1arguments* and create the instance. In general, if the 1signal-name* has an 2eh:make-condition-function* property (which is what 2defsignal* defines), this property is a function to which the 1signal-name* and 1arguments* are passed, and it does the work. Alternatively, the 1signal-name* can be the name of a flavor. Then the 1arguments* are passed to 2make-instance*, which interprets them as init keywords and values. This mode is not really recommended and exists for compatibility with Symbolics software. If the 1signal-name* has no 2eh:make-condition-function* property and is not a flavor name, then a trivial 2defsignal* is assumed as a default. It looks like this: 3(defsignal 1signal-name* ferror ())* So the value is an instance of 2ferror*, with the 1signal-name* as a condition name, and the 1arguments* are interpreted as a format string and args for it. The 1signal-name* 2nil* actually has a definition of this form. 2nil* is frequently used as a signal name in the function 2ferror* when there is no desire to use any condition name in particular. =Node: 4Signaling a Condition Instance* =Text: 3SIGNALING A CONDITION INSTANCE* Once you have a condition instance, you are ready to invoke the condition handling mechanism by signaling it. A condition instance can be signaled any number of times, in any stack groups. 3signal-condition* 1condition-instance* &optional 1proceed-types* 1invoke-debugger* 1ucode-error-status* 1inhibit-resume-handlers* Invoke the condition handling mechanism on 1condition-instance*. The list of 1proceed-types* says which proceed types (among those conventionally defined for the type of condition you have signaled) you are prepared to implement, should a condition handler return one (see ``proceeding''). These are in addition to any proceed types implemented nonlocally by 2condition-resume* forms. 1ucode-error-status* is used for internal purposes in signaling errors detected by the microcode. 2signal-condition* tries various possible handlers for the condition. First 2eh:condition-handlers* is scanned for handlers that are applicable (according to the condition names they specify) to this condition instance. After this list is exhausted, 2eh:condition-default-handlers* is scanned the same way. Each handler that is tried can terminate the act of signaling by throwing out of 2signal-condition*, or it can specify a way to proceed from the signal. The handler can also return 2nil* to decline to handle the condition; then the next possible handler is offered a chance. If all handlers decline to handle the condition and 1invoke-debugger* is non-2nil*, the debugger is the handler of last resort. With the debugger, the user can ask to throw or to proceed. The default value of 1invoke-debugger* is non-2nil* if the 1condition-instance* is an error. If all handlers decline to act and 1invoke-debugger* is 2nil*, 2signal-condition* proceeds using the first proceed type on the list of available ones, provided it is a nonlocal proceed type. If it is a local proceed type, or if there are no proceed types, 2signal-condition* just returns 2nil*. (It would be slightly simpler to proceed using the first proceed type whether it is local or not. But in the case of a local proceed type, this would just mean returning the proceed type instead of 2nil*. It is considered slightly more useful to return 2nil*, allowing the signaler to distinguish the case of a condition not handled. The signaler knows which proceed types it specified, and can if it wishes consider 2nil* as equivalent to the first of them.) Otherwise, by this stage, a proceed type has been chosen from the available list. If the proceed type was among those specified by the caller of 2signal-condition*, then proceeding consists simply of returning to that caller. The chosen proceed type is the first value, and arguments (returned by the handler along with the proceed type) may follow it. If the proceed type was implemented nonlocally with 2condition-resume* (see 4(DEBUGGING-3)Nonlocal Proceed Types*), then the associated proceed handler function on 2eh:condition-resume-handlers* is called. If 1inhibit-resume-handlers* is non-2nil*, resume handlers are not invoked. If a handler returns a nonlocal proceed type, 2signal-condition* just returns to its caller as if the proceed type were local. If the condition is not handled, 2signal-condition* returns 2nil*. The purpose of 2condition-bind-default* is so that you can define a handler that is allowed to handle a signal only if none of the callers' handlers handle it. A more flexible technique for doing this sort of thing is to make an ordinary handler signal the same condition instance recursively by calling 2signal-condition*, like this: 3(multiple-value-list * 3 (signal-condition 1condition-instance** 3 eh:condition-proceed-types nil nil t))* This passes along the same list of proceed types specified by the original signaler, prevents the debugger from being called, and prevents resume handlers from being run. If the first value 2signal-condition* returns is non-2nil*, one of the outer handlers has handled the condition; your handler's simplest option is to return those same values so that the other handler has its way (but it could also examine them and return modified values). Otherwise, you go on to handle the condition in your default manner. 3eh:trace-conditions* 1Variable* This variable may be set to a list of condition names to be 1traced*. Whenever a condition possessing a traced condition name is signaled, an error is signaled to report the fact. (Tracing of conditions is turned off while this error is signaled and handled). Proceeding with proceed type 2:no-action* causes the signaling of the original condition to continue. If 2eh:trace-conditions* is 2t*, all conditions are traced.