Documentation of the "usrhunk" apparatus for SENDing messages. (SSTATUS USRHUNK ) specifies the "user hunk" predicate, which determines whether to "hook into" a user-provided definition for some system facility, or to treat the data strictly as a hunk. (SSTATUS SENDI ) specifies a "SEND" interpreter -- is invoked in order to send a "message" to a "user hunk", when a hunk which passes the "usrhunk" test is given as argument to any of EQUAL SUBST PURCOPY EVAL SXHASH PRINT EXPLODE FLATSIZE ALPHALESSP SAMEPNAMEP NAMESTRING or to any of the following out-of-core facilities GFLATSIZE SPRINT USERATOMS-HOOK DESCRIBE WHICH-OPERATIONS (SSTATUS CALLI ) The usrhunk takes one argument, and should return non-null for objects that LISP should send messages to. It is invoked via (CALL 1,) so this link gets snapped, which means that if you redefine the predicate then the new definition may not take effect unless you un-snap by doing (SSTATUS USRHUNK (STATUS USRHNK)). The usrhunk SEND interpreter, , is invoked via (JCALL 16,) so its link too may be snapped. This function is responsible for delivering the message to the apropriate code for handling it; return values are sometimes significant. See below for documentation on specific messages which will be sent by LISP. Note that an lsubr "SEND" is assumed; this function could be the function that is given to (SSTATUS SENDI ...). For the dozen or so system functions which will send a message to a usrhunk, the action is as follows. Suppose the message is, say, DOIT; then (DOIT ) will be interpreted by doing a send like (SEND 'DOIT ), and this will cause the send interpreter function to select some specialized function, say, FROBULATE, which will then be applied to the arguments in the same order as given to SEND. E.g., (DEFUN FROBULATE (actor msg-key other-arg) (caseq msg-key (DOIT ) (DONT ) (T ))) Actually, the "msg-key" argument could be ignored, but this example shows how several different messages could be dispatched to the same function. The argument spectrum of the frobulator should match that of the original function; thus for the SXHASH message it might be (DEFUN HASH-IT-ALL (ob () ) ...) where the "()" means to ignore the message key (which should be sent as SXHASH). On the other hand, there may be some importance to the order of arguments, as this example for the SUBST message shows: (DEFUN SUBST-FOR-TRICKY-HUNK (hunk () old new) (hunkify (subst old new (extract-data hunk)))) Here is a table of the actions taken by the system functions which resort to SENDing, and of the meanings of the arguments being "sent": EQUAL -- (send obj1 'EQUAL obj2) -- "obj1" and "obj2" are two objects to be compared, and of course "equal" is commutative. SUBST -- (send object 'SUBST a b) -- Substitute a for b in object. PURCOPY -- (send object 'SUBST a b) -- Substitute a for b in object, using static (potentially read-only) consing areas. EVAL -- (send object 'EVAL) -- Return the value of this object. Typically, just returns itself for "implicit quoting". FLATSIZE -- (send object 'FLATSIZE printp level slashifyp) "printp" -- non-null if called from inside print as part of the autoterpri hackery; in this case it should return characters before next legal place to break. This doesn't matter if you're not doing autoterpri hacking. "level" -- fixnum level of recursion of PRINT/FLATSIZE; can be passed on to PRINT-OBJECT or FLATSIZE-OBJECT (see below for their definitions). This is used to limit recursion with PRINLEVEL set non-null. "slashifyp" -- If non-null, include slashes where print would. PRINT -- First, there will be done (send object 'FLATSIZE 'T -1 slashifyp) and then (send object 'PRINT stream level slashifyp) "stream" -- SFA, file, T, or () to print to "level" -- recursion level of PRINT calling print or print methods recursively. If you do printing that may wish to be limited in depth by PRINLEVEL, you should do your output with PRINT-OBJECT, which takes the current nesting level as one of it's arguments. ; "slashify-p" -- if non-null, this is PRIN1, not PRINC EXPLODE -- As with PRINT, there will first be done (send object 'FLATSIZE 'T -1 slashifyp) and then (send object 'EXPLODE slashify-p number-p) "slashify-p" -- non-null if slashes should be output where print would put them. "number-p" -- non-null if characters should be returned as fixnums; otherwise, they are single-character symbols. ALPHALESSP -- Will send either a LESSP or GREATERP message, with one argument, which is the 'other' object for comparison. SAMEPNAMEP -- Sends a SAMEPNAMEP message, with one argument which is the 'other' object for comparison. SXHASH -- Sends a SXHASH message, which should return a FIXNUM to be the SXHASH of the object. NAMESTRING -- Sends a NAMESTRING message, which should return a SYMBOL whose pname characters are a 'namestring' for the object. Two new functions have been added to the initial MacLISP for the sake of recursive calls to PRINT and FLATSIZE by various PRINT and FLATSIZE methods, and they have arguments similarly. PRINT-OBJECT (object level slashifyp stream &optional ignored) FLATSIZE-OBJECT (object printp level slashifyp &optional ignored) "object" -- object to be printed or to have it's FLATSIZE computed. "level" -- recursive printing level, for PRINLEVEL detection. You should pass in the current LEVEL, zero-origen. "slashifyp" -- non-null indicates slashification should be done "stream" -- file or SFA "printp" -- non-null if FLATSIZE is being called originally from PRINT This will be passed in to any FLATSIZE methods called recursively and means "This is a FLATSIZE up to first place OK to break", for print's TERPRI hacking. If you see this and want to punt, return zero. "ignored" -- for compatability with an irrelevant LISPM feature. *** CALLI processing *** CALLI interpreters must be hand coded; they cannot be coded in LISP. This is because of the way they are invoked: They get invoked with the stack in the format for IAPPLY. IAPPLY is LISP's Internal APPLY. The arguments are on the stack, like for an LSUBR call, and T contains the negative of the number of args, just like for an LSUBR call. However, where the return address would be is found the object to be applied. What LISP does is to take that object, figure out how to apply it, replace it's slot on the stack with ,,CPOPJ . CPOPJ is the address of a POPJ P, thus returning to it returns to the caller of the IAPPLY, who's return address is just below that. |arg n |arg n-1 .. .. .. |arg 1 |arg 0 object-to-be-applied return-address Register T (accumulator 6) contains -n, and the slot containing object-to-be-applied is clobbered to ,,CPOPJ and the function is invoked. The user CALLI handler can act in several ways. You can figure out the function you wish to invoke, clobber the slot to contain a CPOPJ (or whatever routine you want executed later) and do a JCALLF 16,(routine) or you can replace the with another object to be used instead, and JRST off to IAPPLY. IAPPLY will then recompute what to do (possibly invoking the user CALLI handler if it answers true to the USRHUNK test), apply the function and return. Since the CALLI handler is not a function, it does not live in a SUBR or LSUBR property, but instead in a CALLI property. (SSTATUS CALLI 'FOO) looks for a CALLI property on FOO. If it finds it, it stores a JRST to that routine internally, and saves the symbol FOO to be returned by (STATUS CALLI). ____________________________________________________________________________ 2/19/80 -- RWK 1) **SELF-EVAL** hook PRINC/PRIN1 now send a FLATC/FLATSIZE message first. This should be improved some more but it really does work. PRINLEVEL info needs to be passed back and forth between MACLISP and user printers, and FLATC/FLATSIZE should be told whether or not it is for PRINT so they can give the FLATC before the first break.