Annotation of 43BSD/ucb/lisp/lisplib/flavors.l, revision 1.1.1.1

1.1       root        1: ; Tasteful Flavors     -*- Mode: Lisp; Package: SI; Base:8 -*-
                      2: 
                      3: ;; (c) copywrite 1982, Massachusetts Institute of Technology
                      4: 
                      5: ;; This flavor system is derived from the original Lisp machine
                      6: ;; flavor system.  As such its distribution may be restricted to
                      7: ;; Lisp machine software license holders.
                      8: 
                      9: (environment-lmlisp (eval compile load) (files flavorm))
                     10: 
                     11: (setq |SCCS-flavors| "@(#) flavors.l   1.1     83/03/14 @(#)")
                     12: 
                     13: (DECLARE (SPECIAL ERRPORT)
                     14:         (MACROS T))
                     15: 
                     16: ; A flavor-name is a symbol which names a type of objects defined
                     17: ; by the combination of several flavors.  The SI:FLAVOR
                     18: ; property is a data-structure (of type FLAVOR) defining the
                     19: ; nature of the flavor, as defined below.
                     20: 
                     21: ; Flavors come in essentially three kinds.  The first kind defines a class
                     22: ; of flavors, and provides the basic instance variables and methods for
                     23: ; that class.  This kind typically includes only VANILLA-FLAVOR as a
                     24: ; component, and uses the :REQUIRED-INSTANCE-VARIABLES and
                     25: ; :REQUIRED-METHODS options.  The second kind of flavor represents a
                     26: ; particular option that may be combined in (a "mix-in").  The third
                     27: ; kind of flavor is the kind that can usefully be instantiated; it is
                     28: ; a combination of one of the first kind and several of the second kind,
                     29: ; to achieve the behavior desired for a particular application.
                     30: 
                     31: ; The following symbols are interesting to outsiders:
                     32: ; DEFFLAVOR - macro for defining a flavor
                     33: ; DEFMETHOD - macro for defining a method
                     34: ; DEFWRAPPER - macro for defining a flavor-wrapper
                     35: ; INSTANTIATE-FLAVOR - create an object of a specified flavor
                     36: ; MAKE-INSTANCE - easier to call version of INSTANTIATE-FLAVOR
                     37: ; COMPILE-FLAVOR-METHODS - macro which does the right thing in the compiler
                     38: ; RECOMPILE-FLAVOR - function to recompile a flavor and maybe any flavors
                     39: ;              that depend on it.  Usually this happens automatically.
                     40: ; FUNCALL-SELF - a macro which, assuming you are a flavor instance, will
                     41: ;              call yourself without bothering about rebinding the
                     42: ;              variables.  Will do something totally random if SELF
                     43: ;              isn't a flavor instance.
                     44: ; LEXPR-FUNCALL-SELF - LEXPR-FUNCALL version of above
                     45: ; *ALL-FLAVOR-NAMES* - list of all symbols which have been used as the 
                     46: ;              name of a flavor
                     47: ; *FLAVOR-COMPILATIONS* - list of all methods which had to be compiled
                     48: ;              this is useful for finding flavors which weren't compiled 
                     49: ;              in qfasl files or which need to be recompiled to bring 
                     50: ;              them up to date.
                     51: ; *FLAVOR-COMPILE-TRACE* - if non-NIL, a FORMAT destination for messages about
                     52: ;              recompilation of combined methods
                     53: ; FLAVOR-ALLOWS-INIT-KEYWORD-P - determine whether a certain flavor allows
                     54: ;              a certain keyword in its init-plist.
                     55: ; FLAVOR-ALLOWED-INIT-KEYWORDS - returns all the init keywords a flavor 
                     56: ;              handles.
                     57: 
                     58: ; Roads not taken:
                     59: ;  o Changing the size of all extant instances of a flavor.
                     60: ;  o Nothing to stop you from instantiating a flavor of the first or
                     61: ;    second kind.  In practice you will usually get an error if you try it.
                     62: 
                     63: ; This macro is used to define a flavor.  Use DEFMETHOD to define
                     64: ; methods (responses to messages sent to an instance of a flavor.)
                     65: (DEFMACRO DEFFLAVOR (NAME INSTANCE-VARIABLES COMPONENT-FLAVORS &REST OPTIONS)
                     66:   ;INSTANCE-VARIABLES can be symbols, or lists of symbol and initialization.
                     67:   ;COMPONENT-FLAVORS are searched from left to right for methods,
                     68:   ; and contribute their instance variables.
                     69:   ;OPTIONS are:
                     70:   ; (:GETTABLE-INSTANCE-VARIABLES v1 v2...) - enables automatic generation of methods
                     71:   ;   for retrieving the values of those instance variables
                     72:   ; :GETTABLE-INSTANCE-VARIABLES - (the atomic form) does it for all instance
                     73:   ;   variables local to this flavor (declared in this DEFFLAVOR).
                     74:   ; (:SETTABLE-INSTANCE-VARIABLES v1 v2...) - enables automatic generation of methods
                     75:   ;   for changing the values of instance variables
                     76:   ;   The atomic form works too.
                     77:   ; (:REQUIRED-INSTANCE-VARIABLES v1 v2...) - any flavor incorporating this
                     78:   ;   flavor and actually instantiated must have instance variables with
                     79:   ;   the specified names.  This is used for defining general types of
                     80:   ;   flavors.
                     81:   ; (:REQUIRED-METHODS m1 m2...) - any flavor incorporating this
                     82:   ;   flavor and actually instantiated must have methods for the specified
                     83:   ;   operations.  This is used for defining general types of flavors.
                     84:   ; (:REQUIRED-FLAVORS f1 f2...) - similar,  for component flavors
                     85:   ;   rather than methods.
                     86:   ; (:INITABLE-INSTANCE-VARIABLES v1 v2...) - these instance variables
                     87:   ;   may be initialized via the options to INSTANTIATE-FLAVOR.
                     88:   ;   The atomic form works too.
                     89:   ;   Settable instance variables are also INITABLE.
                     90:   ; (:INIT-KEYWORDS k1 k2...) - specifies keywords for the :INIT operation
                     91:   ;   which are legal to give to this flavor.  Just used for error checking.
                     92:   ; (:DEFAULT-INIT-PLIST k1 v1 k2 v2...) - specifies defaults to be put
                     93:   ;   into the init-plist, if the keywords k1, k2, ... are not already
                     94:   ;   specified, when instantiating.  The values v1, v2, ... get evaluated
                     95:   ;   when and if they are used.
                     96:   ; (:DEFAULT-HANDLER function) - causes function to be called if a message
                     97:   ;   is sent for which there is no method.  Defaults to a function which
                     98:   ;   gives an error.
                     99:   ; (:INCLUDED-FLAVORS f1 f2...) - specifies flavors to be included in this
                    100:   ;   flavor.  The difference between this and specifying them as components
                    101:   ;   is that included flavors go at the end, so they act as defaults.  This
                    102:   ;   makes a difference when this flavor is depended on by other flavors.
                    103:   ; :NO-VANILLA-FLAVOR - do not include VANILLA-FLAVOR.
                    104:   ;   Normally it is included automatically.  This is for esoteric hacks.
                    105:   ; (:ORDERED-INSTANCE-VARIABLES v1 v2...) - requires that in any instance,
                    106:   ;   instance variables with these names must exist and come first.  This might
                    107:   ;   be for instance variable slots specially referenced by microcode.
                    108:   ;   The atomic form works too.
                    109:   ; (:OUTSIDE-ACCESSIBLE-INSTANCE-VARIABLES v1 v2...) - defines defsubsts which
                    110:   ;   act like defstruct accessors for the variables; that is, using these with
                    111:   ;   an argument of an instance gets the value of that variable in that instance.
                    112:   ;   The name of the defsubst is the flavor-name, hyphen, the variable name.
                    113:   ;   If the instance variable is ordered, the accessor will know its index
                    114:   ;   in the instance and access it directly, otherwise it will call 
                    115:   ;   SYMEVAL-IN-CLOSURE at run-time.
                    116:   ;   The atomic form works too.
                    117:   ; (:ACCESSOR-PREFIX sym) - uses "sym" as the prefix on the names of the above
                    118:   ;   defsubsts instead of "flavor-".
                    119:   ; (:SELECT-METHOD-ORDER m1 m2...) - specifies that the keywords m1, m2, ... are
                    120:   ;   are important and should have their methods first in the select-method
                    121:   ;   table for increased efficiency.
                    122:   ; (:METHOD-COMBINATION (type order operation1 operation2...)...)
                    123:   ;   Specify ways of combining methods from different flavors.  :DAEMON NIL is the
                    124:   ;   the default.  order is usually :BASE-FLAVOR-FIRST or :BASE-FLAVOR-LAST,
                    125:   ;   but this depends on type.
                    126:   ; (:DOCUMENTATION <args>...)
                    127:   ;   The list of args is simply put on the flavor's :DOCUMENTATION property.
                    128:   ;   The standard for this is that the arguments may include keyword symbols and
                    129:   ;   a documentation string.  To be specified more later.
                    130:   ; There may be more.
                    131:   (LET ((COPIED-OPTIONS (COPYLIST OPTIONS)))
                    132:     (DEFFLAVOR1 NAME INSTANCE-VARIABLES COMPONENT-FLAVORS COPIED-OPTIONS)
                    133:     ;; The following is done to determine all the instance variables
                    134:     ;; that need to be declared special.
                    135:     (IF (NOT (NULL (GETD 'LISZT)))
                    136:        (COMPOSE-FLAVOR-COMBINATION (GET-FLAVOR NAME)))
                    137:    `(PROGN 'COMPILE
                    138:      ;; Define flavor at load time.
                    139:      ;; Must come before the compile-time COMPOSE-AUTOMATIC-METHODS,
                    140:      ;; which puts methods in the QFASL file.
                    141:      (EVAL-WHEN (LOAD)
                    142:        (DEFFLAVOR1 ',NAME ',INSTANCE-VARIABLES ',COMPONENT-FLAVORS
                    143:                   ',COPIED-OPTIONS))
                    144:      ,@(COMPOSE-AUTOMATIC-METHODS (GET NAME 'FLAVOR))
                    145: ;; Make any instance-variable accessor macros.
                    146:      ,@(DO ((VS (DO ((OPTS OPTIONS (CDR OPTS)))
                    147:                    ((NULL OPTS) NIL)
                    148:                  (AND (LISTP (CAR OPTS))
                    149:                       (EQ (CAAR OPTS) ':OUTSIDE-ACCESSIBLE-INSTANCE-VARIABLES)
                    150:                       (RETURN (CDAR OPTS)))
                    151:                  (AND (EQ (CAR OPTS) ':OUTSIDE-ACCESSIBLE-INSTANCE-VARIABLES)
                    152:                       (RETURN (MAPCAR #'(LAMBDA (X) (IF (ATOM X) X (CAR X)))
                    153:                                       INSTANCE-VARIABLES))))
                    154:                (CDR VS))
                    155:            (PREFIX (OR (CADR (ASSQ ':ACCESSOR-PREFIX OPTIONS))
                    156:                        (CONCAT NAME "-")))
                    157:            (ORDS (DO ((OPTS OPTIONS (CDR OPTS)))
                    158:                      ((NULL OPTS) NIL)
                    159:                    (AND (LISTP (CAR OPTS))
                    160:                         (EQ (CAAR OPTS) ':ORDERED-INSTANCE-VARIABLES)
                    161:                         (RETURN (CDAR OPTS)))
                    162:                    (AND (EQ (CAR OPTS) ':ORDERED-INSTANCE-VARIABLES)
                    163:                         (RETURN (MAPCAR #'(LAMBDA (X) (IF (ATOM X) X (CAR X)))
                    164:                                         INSTANCE-VARIABLES)))))
                    165:            (RES NIL (CONS `(DEFSUBST ,(INTERN (CONCAT PREFIX (CAR VS)))
                    166:                                      (,NAME)
                    167:                              ,(IF (MEMQ (CAR VS) ORDS)
                    168: ; SMH@EMS VVV                     `(VREF ,NAME
                    169: ;                                        ,(+ 9 (* 3 (FIND-POSITION-IN-LIST
                    170: ;                                                    (CAR VS) ORDS))))
                    171:                                   `(INT:FCLOSURE-STACK-STUFF
                    172:                                     (VREF ,NAME ,(+ 3 (FIND-POSITION-IN-LIST
                    173:                                                        (CAR VS) ORDS))))
                    174: ; SMH@EMS ^^^
                    175:                                   `(SYMEVAL-IN-FCLOSURE ,NAME ',(CAR VS))))
                    176:                           RES)))
                    177:           ((NULL VS) RES))
                    178:      ',NAME)))
                    179: 
                    180: (DEFMACRO DEFUN-METHOD (FSPEC FLAVOR-NAME ARGLIST &BODY BODY)
                    181:   `(DEFUN ,FSPEC ,ARGLIST
                    182:      (DECLARE (SPECIAL SELF .OWN-FLAVOR.
                    183:                       ,@(FLAVOR-ALL-INSTANCE-VARIABLES
                    184:                          (GET-FLAVOR FLAVOR-NAME))))
                    185:      . ,BODY))
                    186: 
                    187: (DEFMACRO INSTANCE-VARIABLE-BOUNDP (X)
                    188:   `(BOUNDP ',X))
                    189: 
                    190: (DEFVAR *ALL-FLAVOR-NAMES* NIL)        ;List of names of all flavors (mostly for editor)
                    191: 
                    192: (DEFVAR *USE-OLD-COMBINED-METHODS* T)
                    193:  ;;T means recycle old, NIL means generate new. 
                    194:  ;; This is an implicit argument to certain routines. 
                    195: 
                    196: (DEFVAR *FLAVOR-PENDING-DEPENDS* NIL)  ;Used by DEFFLAVOR1
                    197: 
                    198: (DEFVAR *FLAVOR-COMPILATIONS* NIL)     ;List of methods compiled
                    199: 
                    200: (DEFVAR *FLAVOR-COMPILE-TRACE* NIL)
                    201: 
                    202: (DEFSUBST INSTANCE-FLAVOR (INSTANCE)
                    203:   (SYMEVAL-IN-FCLOSURE INSTANCE '.OWN-FLAVOR.))
                    204: 
                    205: (DEFSUBST INSTANCE-FUNCTION (INSTANCE)
                    206:   (FCLOSURE-FUNCTION INSTANCE))
                    207: 
                    208: (DEFUN GET-FLAVOR (FLAVOR-OR-NAME &AUX TEMP)
                    209:   (COND ((:TYPEP FLAVOR-OR-NAME 'FLAVOR) FLAVOR-OR-NAME)
                    210:        ((SYMBOLP FLAVOR-OR-NAME)
                    211:         (SETQ TEMP (GET FLAVOR-OR-NAME 'FLAVOR))
                    212:         (CHECK-ARG FLAVOR-OR-NAME (:TYPEP TEMP 'FLAVOR)
                    213:                    "the name of a flavor")
                    214:         TEMP)
                    215:        (T (CHECK-ARG FLAVOR-OR-NAME (:TYPEP TEMP 'FLAVOR)
                    216:                      "the name of a flavor"))))
                    217: 
                    218: ;;(DEFSUBST INSTANCEP (X)
                    219: ;;  (AND (FCLOSUREP X) (EQ (FCLOSURE-FUNCTION X) #'FLAVOR-DISPATCH)))
                    220: 
                    221: (DEFUN INSTANCE-TYPEP (OB TYPE)
                    222:   (IF (NULL TYPE)
                    223:       (FLAVOR-NAME (INSTANCE-FLAVOR OB))
                    224:       (NOT (NULL (MEMQ TYPE (FLAVOR-DEPENDS-ON-ALL
                    225:                             (INSTANCE-FLAVOR OB)))))))
                    226:   
                    227: 
                    228: ;These properties are not discarded by redoing a DEFFLAVOR.
                    229: (DEFCONST DEFFLAVOR1-PRESERVED-PROPERTIES
                    230:          '(ADDITIONAL-INSTANCE-VARIABLES
                    231:            COMPILE-FLAVOR-METHODS
                    232:            MAPPED-COMPONENT-FLAVORS
                    233:            INSTANCE-VARIABLE-INITIALIZATIONS
                    234:            ALL-INITABLE-INSTANCE-VARIABLES
                    235:            REMAINING-DEFAULT-PLIST
                    236:            REMAINING-INIT-KEYWORDS))
                    237: 
                    238: ;These are instance variables that don't belong to this flavor or its components
                    239: ;but can be accessed by methods of this flavor.
                    240: (DEFSUBST FLAVOR-ADDITIONAL-INSTANCE-VARIABLES (FLAVOR)
                    241:   (GET (FLAVOR-PLIST FLAVOR) 'ADDITIONAL-INSTANCE-VARIABLES))
                    242: 
                    243: ;The next four are distillations of info taken from this flavor and its components,
                    244: ;used for instantiating this flavor.  See COMPOSE-FLAVOR-INITIALIZATIONS.
                    245: (DEFSUBST FLAVOR-INSTANCE-VARIABLE-INITIALIZATIONS (FLAVOR)
                    246:   (GET (FLAVOR-PLIST FLAVOR) 'INSTANCE-VARIABLE-INITIALIZATIONS))
                    247: 
                    248: (DEFSUBST FLAVOR-REMAINING-DEFAULT-PLIST (FLAVOR)
                    249:   (GET (FLAVOR-PLIST FLAVOR) 'REMAINING-DEFAULT-PLIST))
                    250: 
                    251: (DEFSUBST FLAVOR-REMAINING-INIT-KEYWORDS (FLAVOR)
                    252:   (GET (FLAVOR-PLIST FLAVOR) 'REMAINING-INIT-KEYWORDS))
                    253: 
                    254: (DEFSUBST FLAVOR-ALL-INITABLE-INSTANCE-VARIABLES (FLAVOR)
                    255:   (GET (FLAVOR-PLIST FLAVOR) 'ALL-INITABLE-INSTANCE-VARIABLES))
                    256: 
                    257: (DEFUN (FLAVOR :NAMED-STRUCTURE-INVOKE) (OPERATION &OPTIONAL SELF &REST ARGS)
                    258:   (SELECTQ OPERATION
                    259:           (:WHICH-OPERATIONS '(:PRINT-SELF :DESCRIBE))
                    260:           (:PRINT-SELF
                    261:            (SI:PRINTING-RANDOM-OBJECT (SELF (CAR ARGS))
                    262:               (FORMAT (CAR ARGS) "FLAVOR ~S" (FLAVOR-NAME SELF))))
                    263:           (:DESCRIBE (DESCRIBE-FLAVOR SELF))
                    264:           (OTHERWISE
                    265:            (FERROR NIL "~S UNKNOWN OPERATION FOR FLAVOR" OPERATION))))
                    266: 
                    267: ;Format of flavor-method-table:
                    268: ; New format of a flavor-method-table entry is:
                    269: ;   (message combination-type combination-order meth...)
                    270: ; A meth is:
                    271: ;   (function-spec definition plist)
                    272: ; Thus the second element of a meth is actually a function-cell.
                    273: ; The meth's are stored in permanent-storage-area so that they will be compact.
                    274: ;    [That might not be the best area, the select-methods, and component
                    275: ;     lists, and instanc-variable lists, and which-operations's, are also there.]
                    276: ; A magic-list entry is:
                    277: ;   (message combination-type combination-order (method-type function-spec...)...)
                    278: ; In the magic-list, there can be more than one method listed under a method-type,
                    279: ; the base flavor always comes first.  The :COMBINED methods are elided from
                    280: ; the magic-list.
                    281: ;
                    282: ; Special method-types:
                    283: ;   NIL - no type specified
                    284: ;   :DEFAULT - like NIL but only taken if there are no type-NIL methods
                    285: ;   :WRAPPER - wrappers are remembered this way
                    286: ;   :COMBINED - a daemon-caller; the symbol has a COMBINED-METHOD-DERIVATION property
                    287: ;              whose value is the complete method table entry from the magic-list.
                    288: ;              The CDDDR is canonicalized; each contained list of method symbols is
                    289: ;              of course ordered by the order in which flavors are combined (base
                    290: ;              flavor first).  Canonical order is alphabetical by method-type.
                    291: ; Non-special method-types:
                    292: ;   :BEFORE, :AFTER - these are used by the default combination-type, :DAEMON
                    293: ;
                    294: ; Special hair for wrappers: changing a wrapper can invalidate the combined method
                    295: ; without changing anything in the flavor-method-table entry.  Rather than having
                    296: ; it automatically recompile, which turns out to be a pain when the wrapper was
                    297: ; just reloaded or changed trivially, it will fail to recompile and you must use
                    298: ; RECOMPILE-FLAVOR with a 3rd argument of NIL.
                    299: ;
                    300: ; A combination-type of NIL means it has not been explicitly specified.
                    301: 
                    302: ; Method-combination functions.  Found on the SI:METHOD-COMBINATION property
                    303: ; of the combination-type.  These are passed the flavor structure, and the
                    304: ; magic-list entry, and must return the function spec to use as the handler.
                    305: ; It should also define or compile thew definition for that function spec if nec.
                    306: ; This function interprets combination-type-arg,
                    307: ; which for many combination-types is either :BASE-FLAVOR-FIRST or :BASE-FLAVOR-LAST.
                    308: 
                    309: ;This is an a-list from method type to function to write the code to go
                    310: ;in the combined method.  Users can add to this.
                    311: (DEFCONST *SPECIALLY-COMBINED-METHOD-TYPES*
                    312:          '((:WRAPPER PUT-WRAPPER-INTO-COMBINED-METHOD)))
                    313: 
                    314: ;Definitions of a meth (the datum which stands for a method)
                    315: 
                    316: (DEFSTRUCT (METH :LIST :CONC-NAME (:CONSTRUCTOR NIL))
                    317:                ;No constructor because defstruct doesn't let me specify the area
                    318:   FUNCTION-SPEC
                    319:   DEFINITION
                    320:   (PLIST NIL))
                    321: 
                    322: ; If there is no definition, it contains DTP-NULL and a pointer to the meth
                    323: 
                    324: ; Extract the method-type of a meth
                    325: (DEFMACRO METH-METHOD-TYPE (METH)
                    326:   `(AND (CDDDR (METH-FUNCTION-SPEC ,METH))
                    327:        (THIRD (METH-FUNCTION-SPEC ,METH))))
                    328: 
                    329: ; Return a meth of specified type from a list of meth's.
                    330: (DEFUN METH-LOOKUP (METHOD-TYPE METH-LIST)
                    331:   (LOOP FOR METH IN METH-LIST
                    332:        WHEN (EQ (METH-METHOD-TYPE METH) METHOD-TYPE)
                    333:          RETURN METH))
                    334: 
                    335: (DEFUN NULLIFY-METHOD-DEFINITION (METH)
                    336:   (SETF (METH-DEFINITION METH) NIL))
                    337: 
                    338: (DEFUN METH-DEFINEDP (METH)
                    339:   (NOT (NULL (METH-DEFINITION METH))))
                    340: 
                    341: ;Function to define or redefine a flavor (used by DEFFLAVOR macro).
                    342: ;Note that to ease initialization problems, the flavors depended upon need
                    343: ;not be defined yet.  You will get an error the first time you try to create
                    344: ;an instance of this flavor if a flavor it depends on is still undefined.
                    345: ;When redefining a flavor, we reuse the same FLAVOR defstruct so that
                    346: ;old instances continue to get the latest methods, unless you change
                    347: ;something incompatibly, in which case you will get a warning.
                    348: (DEFUN DEFFLAVOR1 (FLAVOR-NAME INSTANCE-VARIABLES COMPONENT-FLAVORS OPTIONS
                    349:                   &AUX FFL ALREADY-EXISTS INSTV IDENTICAL-COMPONENTS
                    350:                        GETTABLE SETTABLE INITABLE OLD-DEFAULT-HANDLER
                    351:                        OLD-DEFAULT-INIT-PLIST OLD-LOCAL-IVS OLD-INITABLE-IVS
                    352:                        OLD-INIT-KWDS
                    353:                        INIT-KEYWORDS INCLUDES METH-COMB
                    354:                        (PL (LIST 'FLAVOR-PLIST)))
                    355:   (COND ((NOT (MEMQ FLAVOR-NAME *ALL-FLAVOR-NAMES*))
                    356:         (PUSH FLAVOR-NAME *ALL-FLAVOR-NAMES*)))
                    357:   ;; Analyze and error check the instance-variable and component-flavor lists
                    358:   (SETQ INSTV (MAPCAR #'(LAMBDA (X) (IF (ATOM X) X (CAR X)))
                    359:                      INSTANCE-VARIABLES))
                    360:   (DOLIST (IV INSTV)
                    361:     (IF (OR (NULL IV) (NOT (SYMBOLP IV)))
                    362:        (FERROR () "~S, which is not a symbol, was specified as an instance variable" IV)))
                    363:   (DOLIST (CF COMPONENT-FLAVORS)
                    364:     (IF (OR (NULL CF) (NOT (SYMBOLP CF)))
                    365:        (FERROR () "~S, which is not a symbol, was specified as a component flavor" CF)))
                    366:   ;; Certain properties are inherited from the old property list, while
                    367:   ;; others are generated afresh each time from the defflavor-options.
                    368:   (COND ((SETQ ALREADY-EXISTS (GET FLAVOR-NAME 'FLAVOR))
                    369:         (DOLIST (PROP DEFFLAVOR1-PRESERVED-PROPERTIES)
                    370:           (PUTPROP PL (GET (FLAVOR-PLIST ALREADY-EXISTS) PROP)
                    371:                    PROP))))
                    372:   ;; First, parse all the defflavor options into local variables so we can see
                    373:   ;; whether the flavor is being redefined incompatibly.
                    374:   (DO ((L OPTIONS (CDR L))
                    375:        (OPTION) (ARGS))
                    376:       ((NULL L))
                    377:     (IF (ATOM (CAR L))
                    378:        (SETQ OPTION (CAR L) ARGS NIL)
                    379:        (SETQ OPTION (CAAR L) ARGS (CDAR L)))
                    380:     (SELECTQ OPTION
                    381:        (:GETTABLE-INSTANCE-VARIABLES
                    382:          (VALIDATE-INSTANCE-VARIABLES-SPEC ARGS INSTV FLAVOR-NAME OPTION)
                    383:          (SETQ GETTABLE (OR ARGS INSTV)))
                    384:        (:SETTABLE-INSTANCE-VARIABLES
                    385:          (VALIDATE-INSTANCE-VARIABLES-SPEC ARGS INSTV FLAVOR-NAME OPTION)
                    386:          (SETQ SETTABLE (OR ARGS INSTV)))
                    387:        ((:INITABLE-INSTANCE-VARIABLES :INITABLE-INSTANCE-VARIABLES)
                    388:          (VALIDATE-INSTANCE-VARIABLES-SPEC ARGS INSTV FLAVOR-NAME OPTION)
                    389:          (SETQ INITABLE (OR ARGS INSTV)))
                    390:        (:SPECIAL-INSTANCE-VARIABLES)  ; Ignored since all IVs are special
                    391:        (:INIT-KEYWORDS
                    392:          (SETQ INIT-KEYWORDS ARGS))
                    393:        (:INCLUDED-FLAVORS
                    394:          (SETQ INCLUDES ARGS))
                    395:        (:NO-VANILLA-FLAVOR
                    396:          (PUTPROP PL T OPTION))
                    397:        (:ORDERED-INSTANCE-VARIABLES
                    398:          ;Don't validate.  User may reasonably want to specify non-local instance
                    399:          ;variables, and any bogus names here will get detected by COMPOSE-FLAVOR-COMBINATION
                    400:          ;(VALIDATE-INSTANCE-VARIABLES-SPEC ARGS INSTV FLAVOR-NAME OPTION)
                    401:          (PUTPROP PL (OR ARGS INSTV) ':ORDERED-INSTANCE-VARIABLES))
                    402:        (:OUTSIDE-ACCESSIBLE-INSTANCE-VARIABLES
                    403:          (VALIDATE-INSTANCE-VARIABLES-SPEC ARGS INSTV FLAVOR-NAME OPTION)
                    404:          (PUTPROP PL (OR ARGS INSTV) ':OUTSIDE-ACCESSIBLE-INSTANCE-VARIABLES))
                    405:        (:METHOD-COMBINATION
                    406:          (SETQ METH-COMB ARGS))
                    407:        (:DEFAULT-HANDLER
                    408:          (PUTPROP PL (CAR ARGS) OPTION))
                    409:        ((:REQUIRED-INSTANCE-VARIABLES :REQUIRED-METHODS :REQUIRED-FLAVORS :DOCUMENTATION
                    410:          :DEFAULT-INIT-PLIST :SELECT-METHOD-ORDER :ACCESSOR-PREFIX)
                    411:          (PUTPROP PL ARGS OPTION))
                    412:        (OTHERWISE (FERROR () "~S unknown option to DEFFLAVOR" OPTION))))
                    413:   ;; All settable instance variables should also be gettable and INITABLE.
                    414:   (DOLIST (V SETTABLE)
                    415:     (OR (MEMQ V GETTABLE)
                    416:        (PUSH V GETTABLE))
                    417:     (OR (MEMQ V INITABLE)
                    418:        (PUSH V INITABLE)))
                    419:   ;; See whether there are any changes in component flavor structure from last time
                    420:   (SETQ IDENTICAL-COMPONENTS
                    421:        (AND ALREADY-EXISTS
                    422:             (EQUAL COMPONENT-FLAVORS (FLAVOR-DEPENDS-ON ALREADY-EXISTS))
                    423:             (EQUAL INCLUDES (FLAVOR-INCLUDES ALREADY-EXISTS))
                    424:             (EQUAL (GET PL ':REQUIRED-FLAVORS)
                    425:                    (GET (FLAVOR-PLIST ALREADY-EXISTS) ':REQUIRED-FLAVORS))))   
                    426:   (AND ALREADY-EXISTS
                    427:        (SETQ OLD-DEFAULT-HANDLER (GET (FLAVOR-PLIST ALREADY-EXISTS)
                    428:                                      ':DEFAULT-HANDLER)
                    429:             OLD-DEFAULT-INIT-PLIST (GET (FLAVOR-PLIST ALREADY-EXISTS)
                    430:                                         ':DEFAULT-INIT-PLIST)
                    431:             OLD-LOCAL-IVS (FLAVOR-LOCAL-INSTANCE-VARIABLES ALREADY-EXISTS)
                    432:             OLD-INITABLE-IVS (FLAVOR-INITABLE-INSTANCE-VARIABLES ALREADY-EXISTS)
                    433:             OLD-INIT-KWDS (FLAVOR-INIT-KEYWORDS ALREADY-EXISTS))) 
                    434:   ;; If the flavor is being redefined, and the number or order of instance 
                    435:   ;; variables is being changed, and this flavor or any that depends on it
                    436:   ;; has a select-method table (i.e. has probably been instantiated), give 
                    437:   ;; a warning and disconnect from the old FLAVOR defstruct so that old 
                    438:   ;; instances will retain the old information.  The instance variables can 
                    439:   ;; get changed either locally or by rearrangement of the component flavors.
                    440:   (AND ALREADY-EXISTS
                    441:        (IF (AND (EQUAL (GET PL ':ORDERED-INSTANCE-VARIABLES)
                    442:                       (GET (FLAVOR-PLIST ALREADY-EXISTS)
                    443:                            ':ORDERED-INSTANCE-VARIABLES))
                    444:                (OR (EQUAL (FLAVOR-LOCAL-INSTANCE-VARIABLES ALREADY-EXISTS)
                    445:                           INSTANCE-VARIABLES)
                    446:                    (EQUAL (MAPCAR #'(LAMBDA (X) (IF (ATOM X) X (CAR X)))
                    447:                                   (FLAVOR-LOCAL-INSTANCE-VARIABLES ALREADY-EXISTS))
                    448:                           INSTV))
                    449:                (OR IDENTICAL-COMPONENTS
                    450:                    (EQUAL (FLAVOR-RELEVANT-COMPONENTS ALREADY-EXISTS
                    451:                                                       COMPONENT-FLAVORS INCLUDES)
                    452:                           (FLAVOR-RELEVANT-COMPONENTS ALREADY-EXISTS
                    453:                                                       (FLAVOR-DEPENDS-ON ALREADY-EXISTS)
                    454:                                                       (FLAVOR-INCLUDES ALREADY-EXISTS)))))
                    455:           NIL
                    456:           (SETQ ALREADY-EXISTS (PERFORM-FLAVOR-REDEFINITION FLAVOR-NAME))))
                    457:   ;; Make the information structure unless the flavor already exists.
                    458:   (LET ((FL (OR ALREADY-EXISTS
                    459:                (GET FLAVOR-NAME 'UNDEFINED-FLAVOR)
                    460:                (MAKE-FLAVOR FLAVOR-NAME FLAVOR-NAME))))
                    461:     (SETF (FLAVOR-LOCAL-INSTANCE-VARIABLES FL) INSTANCE-VARIABLES)
                    462:     (SETF (FLAVOR-DEPENDS-ON FL) COMPONENT-FLAVORS)
                    463:     (SETF (FLAVOR-PLIST FL) PL)
                    464:     (IF GETTABLE
                    465:        (SETF (FLAVOR-GETTABLE-INSTANCE-VARIABLES FL) GETTABLE))
                    466:     (IF SETTABLE
                    467:        (SETF (FLAVOR-SETTABLE-INSTANCE-VARIABLES FL) SETTABLE))
                    468:     (SETF (FLAVOR-INITABLE-INSTANCE-VARIABLES FL)
                    469:          (LOOP FOR V IN INITABLE COLLECT (CONS (CORRESPONDING-KEYWORD V) V)))
                    470:     (SETF (FLAVOR-INIT-KEYWORDS FL) INIT-KEYWORDS)
                    471:     (SETF (FLAVOR-INCLUDES FL) INCLUDES)
                    472:     ;; First remove old method-combination declarations, then add new ones
                    473:     (DOLIST (MTE (FLAVOR-METHOD-TABLE FL))
                    474:       (COND ((LOOP FOR DECL IN METH-COMB NEVER (MEMQ (CAR MTE) (CDDR DECL)))
                    475:             (SETF (SECOND MTE) NIL)
                    476:             (SETF (THIRD MTE) NIL))))
                    477:     (DOLIST (DECL METH-COMB)
                    478:       (LET ((TYPE (CAR DECL)) (ORDER (CADR DECL)) ELEM)
                    479:        ;; Don't error-check TYPE now, its definition might not be loaded yet
                    480:        (DOLIST (MSG (CDDR DECL))
                    481:          (OR (SETQ ELEM (ASSQ MSG (FLAVOR-METHOD-TABLE FL)))
                    482:              (PUSH (SETQ ELEM (LIST* MSG NIL NIL NIL)) (FLAVOR-METHOD-TABLE FL)))
                    483:          (SETF (SECOND ELEM) TYPE)
                    484:          (SETF (THIRD ELEM) ORDER))))
                    485:     ;; Make this a depended-on-by of its depends-on, or remember to do it 
                    486:     ;; later in the case of depends-on's not yet defined.
                    487:     (DOLIST (COMPONENT-FLAVOR COMPONENT-FLAVORS)
                    488:       (COND ((SETQ FFL (GET COMPONENT-FLAVOR 'FLAVOR))
                    489:             (OR (MEMQ FLAVOR-NAME (FLAVOR-DEPENDED-ON-BY FFL))
                    490:                 (PUSH FLAVOR-NAME (FLAVOR-DEPENDED-ON-BY FFL))))
                    491:            (T (PUSH (CONS COMPONENT-FLAVOR FLAVOR-NAME)
                    492:                     *FLAVOR-PENDING-DEPENDS*))))
                    493:     ;; Likewise for its includes
                    494:     (DOLIST (INCLUDED-FLAVOR (FLAVOR-INCLUDES FL))
                    495:       (COND ((SETQ FFL (GET INCLUDED-FLAVOR 'FLAVOR))
                    496:             (OR (MEMQ FLAVOR-NAME (FLAVOR-DEPENDED-ON-BY FFL))
                    497:                 (PUSH FLAVOR-NAME (FLAVOR-DEPENDED-ON-BY FFL))))
                    498:            (T (PUSH (CONS INCLUDED-FLAVOR FLAVOR-NAME)
                    499:                     *FLAVOR-PENDING-DEPENDS*))))
                    500:     ;; If someone depends on this flavor, which wasn't defined until now, 
                    501:     ;; link them up.  If that flavor was flavor-composed, recompose it now.
                    502:     (DOLIST (X *FLAVOR-PENDING-DEPENDS*)
                    503:       (COND ((EQ (CAR X) FLAVOR-NAME)
                    504:             (OR (MEMQ (CDR X) (FLAVOR-DEPENDED-ON-BY FL))
                    505:                 (PUSH (CDR X) (FLAVOR-DEPENDED-ON-BY FL)))
                    506:             (SETQ *FLAVOR-PENDING-DEPENDS*
                    507:                   (DELQ X *FLAVOR-PENDING-DEPENDS*)))))
                    508:     (PUTPROP FLAVOR-NAME FL 'FLAVOR)
                    509:     ;; Now, if the flavor was redefined in a way that changes the methods but
                    510:     ;; doesn't invalidate old instances, we have to propagate some changes.
                    511:     (IF (AND ALREADY-EXISTS
                    512:             (NOT IDENTICAL-COMPONENTS))
                    513:        (PERFORM-FLAVOR-METHOD-ONLY-REDEFINITION FLAVOR-NAME))
                    514:     FLAVOR-NAME))
                    515: 
                    516: ;Check for typos in user-specified lists of instance variables.
                    517: ;This assumes that only locally-specified (not inherited) instance variables
                    518: ;may be mentioned in DEFFLAVOR declaration clauses.
                    519: (DEFUN VALIDATE-INSTANCE-VARIABLES-SPEC (VARS-SPECD VARS-ALLOWED FLAVOR-NAME
                    520:                                                    OPTION &AUX BAD)
                    521:   (DOLIST (VAR VARS-SPECD)
                    522:     (OR (MEMQ VAR VARS-ALLOWED) (PUSH VAR BAD)))
                    523:   (COND (BAD (FORMAT ERRPORT "~&ERROR: Flavor ~S has misspelled :~A ~%~S"
                    524:                     FLAVOR-NAME OPTION (NREVERSE BAD)))))
                    525: 
                    526: ;List of those components which affect the names, number, and ordering of the
                    527: ;instance variables.  Don't worry about undefined components, by definition
                    528: ;they must be different from the already-existing flavor, so the right
                    529: ;thing will happen.  (I wonder what that comment means?  Undefined components
                    530: ;will not even appear in the list.)
                    531: (DEFUN FLAVOR-RELEVANT-COMPONENTS (FL COMPONENT-FLAVORS INCLUDED-FLAVORS)
                    532:   (SETF (FLAVOR-DEPENDS-ON FL) COMPONENT-FLAVORS)
                    533:   (SETF (FLAVOR-INCLUDES FL) INCLUDED-FLAVORS)
                    534:   (DEL-IF-NOT #'(LAMBDA (FLAVOR)       ;Splice out the uninteresting ones
                    535:                  (FLAVOR-LOCAL-INSTANCE-VARIABLES FLAVOR))
                    536:              (COMPOSE-FLAVOR-INCLUSION (FLAVOR-NAME FL) NIL)))
                    537: 
                    538: ;; Now that default structs are vectors, and plain copy works for vectors,
                    539: ;; this has been removed and replaced by copy. - SMH@EMS
                    540: ;(DEFUN COPY-HUNK-CONTENTS (H1 H2)
                    541: ;  (LOOP FOR I FROM 0 TO (1- (HUNKSIZE H2))
                    542: ;      DO (SETF (CXR I H2) (CXR I H1))))
                    543: 
                    544: ;Propagate things from an old flavor to a new one which we construct,
                    545: ;for compiling a file.
                    546: (DEFUN FLAVOR-REDEFINITION-FOR-COMPILATION (OLD-FLAVOR NEW-COMPONENTS-P)
                    547:   NEW-COMPONENTS-P
                    548:   (LET ((NEW-FLAVOR (MAKE-FLAVOR FLAVOR-NAME (FLAVOR-NAME OLD-FLAVOR))))
                    549:     ;(COPY-HUNK-CONTENTS OLD-FLAVOR NEW-FLAVOR) ; SMH@EMS
                    550:     (SETQ NEW-FLAVOR (COPY OLD-FLAVOR))        ; Now works only if vector.
                    551:     ;; Do copy any combined methods.  If we have dependents also in this file
                    552:     ;; and they have COMPILE-FLAVOR-METHODS in this file,
                    553:     ;; they will want to see our combined methods in case they can use them.
                    554:     (COPY-METHOD-TABLE OLD-FLAVOR NEW-FLAVOR NIL)
                    555:     (SETF (FLAVOR-DEPENDS-ON-ALL NEW-FLAVOR) NIL)      ;Will need to be flavor-composed again
                    556:     ;; Cause an error if these are looked at before they are valid.
                    557:     (SETF (FLAVOR-ALL-INSTANCE-VARIABLES NEW-FLAVOR) 'NOT-COMPUTED)
                    558:     (SETF (FLAVOR-DEPENDED-ON-BY NEW-FLAVOR) 'COMPILATION)
                    559:     (SETF (FLAVOR-METHOD-HASH-TABLE NEW-FLAVOR) NIL)   ;Will need to be method-composed again
                    560:     (SETF (FLAVOR-WHICH-OPERATIONS NEW-FLAVOR) NIL)
                    561:     NEW-FLAVOR))
                    562: 
                    563: (DEFUN COPY-METHOD-TABLE (OLD-FLAVOR NEW-FLAVOR DISCARD-COMBINED-METHODS)
                    564:   (LET ((L (COPYLIST (FLAVOR-METHOD-TABLE OLD-FLAVOR))))
                    565:     (DO ((TAIL L (CDR TAIL)))
                    566:        ((NULL TAIL))
                    567:       ;; Copy the method-table element, including the list of METH's.
                    568:       (SETF (CAR TAIL) (COPYLIST (CAR TAIL)))
                    569:       (IF DISCARD-COMBINED-METHODS
                    570:          ;; Flush from the copy all combined methods.
                    571:          (DO ((TAIL2 (CDDDR (CAR TAIL)) (CDR TAIL2)))
                    572:              ((NULL TAIL2))
                    573:            (AND (EQ (METH-METHOD-TYPE (CAR TAIL2)) ':COMBINED)
                    574:                 (SETF (CDDDAR TAIL)
                    575:                       (DELQ (CAR TAIL2) (CDDDAR TAIL))))))
                    576:       ;; Now copy each METH that we didn't delete.
                    577:       ;; Copying a METH is not trivial because it can contain a DTP-NULL.
                    578:       (DO ((TAIL2 (CDDDR (CAR TAIL)) (CDR TAIL2)))
                    579:          ((NULL TAIL2))
                    580:        (LET ((NEW-METH (LIST (FIRST (CAR TAIL2))
                    581:                              NIL
                    582:                              (COPYLIST (THIRD (CAR TAIL2))))))
                    583:          (IF (METH-DEFINEDP (CAR TAIL2))
                    584:              (SETF (METH-DEFINITION NEW-METH) (METH-DEFINITION (CAR TAIL2)))
                    585:            (NULLIFY-METHOD-DEFINITION NEW-METH))
                    586:          (SETF (CAR TAIL2) NEW-METH))))
                    587:     (SETF (FLAVOR-METHOD-TABLE NEW-FLAVOR) L)))
                    588: 
                    589: ;Record a flavor definition, during compiling a file.
                    590: ;Instead of setting the name's FLAVOR property, we put an entry on the
                    591: ;FLAVORS element in the FILE-LOCAL-DECLARATIONS, where COMPILATION-FLAVOR looks.
                    592: (DEFVAR FILE-LOCAL-DECLARATIONS ())
                    593: 
                    594: (DEFUN COMPILATION-DEFINE-FLAVOR (FLAVOR-NAME FL)
                    595:   (LET ((FLL (ASSQ 'FLAVORS FILE-LOCAL-DECLARATIONS)))
                    596:     (COND ((NULL FLL)
                    597:           (PUSH (NCONS 'FLAVORS) FILE-LOCAL-DECLARATIONS)
                    598:           (SETQ FLL (CAR FILE-LOCAL-DECLARATIONS))))
                    599:     (PUTPROP FLL FL FLAVOR-NAME)))
                    600: 
                    601: ;Call here when a flavor has been changed in a way that is not compatible
                    602: ;with old instances of this flavor or its dependents.
                    603: ;Arranges for those old instances to keep the old flavor structures and 
                    604: ;methods.  Return new copy of the FLAVOR defstruct, and propagate to those 
                    605: ;that depend on it.  Note that we tell copy-method-table to discard our 
                    606: ;combined methods.  This is because they point to METHs in our method table,
                    607: ;so we must make new combined methods that point at our new method table.
                    608: (DEFUN PERFORM-FLAVOR-REDEFINITION (FLAVOR-NAME &AUX FL NFL)
                    609:   (SETQ FL (GET FLAVOR-NAME 'FLAVOR))
                    610:   (COND ((FLAVOR-METHOD-HASH-TABLE FL)
                    611:         (SETQ NFL (MAKE-FLAVOR))
                    612:         ; (COPY-HUNK-CONTENTS FL NFL) ; SMH@EMS
                    613:         (SETQ NFL (COPY FL))           ; Now works only if FL is a vector!
                    614:         (COPY-METHOD-TABLE FL NFL T)                      ;Copy, but discard combined methods
                    615:         (SETQ FL NFL)
                    616:         (SETF (FLAVOR-PLIST FL) (COPYLIST (FLAVOR-PLIST FL)))
                    617:         (PUTPROP FLAVOR-NAME FL 'FLAVOR)
                    618:         (FORMAT ERRPORT "~&Flavor ~S changed incompatibly, old instances will not get the new version.~%"
                    619:                 FLAVOR-NAME))
                    620:        ;; Even if this flavor wasn't instantiated,
                    621:        ;; probably some of its dependents were,
                    622:        ;; and their hash tables and combined methods point to our method table.
                    623:        (T (COPY-METHOD-TABLE FL FL T)))
                    624:   (SETF (FLAVOR-DEPENDS-ON-ALL FL) NIL)        ;Will need to be flavor-composed again
                    625:   (SETF (FLAVOR-METHOD-HASH-TABLE FL) NIL)     ;Will need to be method-composed again
                    626:   (SETF (FLAVOR-WHICH-OPERATIONS FL) NIL)
                    627:   (DOLIST (FN (FLAVOR-DEPENDED-ON-BY FL))
                    628:     (PERFORM-FLAVOR-REDEFINITION FN))
                    629:   FL)
                    630: 
                    631: ;This one is when the old instances don't have to be discarded, but recomposition
                    632: ;does have to occur because something was changed in the order of flavor combination
                    633: (DEFUN PERFORM-FLAVOR-METHOD-ONLY-REDEFINITION (FLAVOR-NAME)
                    634:   (LET ((FDEFINE-FILE-PATHNAME NIL))   ;Don't give warnings for combined methods
                    635:     ;; Reverse the list so that this flavor comes first, followed by directest descendents.
                    636:     (DOLIST (FN (REVERSE (FLAVOR-DEPENDED-ON-BY-ALL (GET FLAVOR-NAME 'FLAVOR)
                    637:                                                    (LIST FLAVOR-NAME))))
                    638:       (LET ((FL (GET FN 'FLAVOR)))
                    639:        (IF (FLAVOR-DEPENDS-ON-ALL FL) (COMPOSE-FLAVOR-COMBINATION FL))
                    640:        (IF (FLAVOR-METHOD-HASH-TABLE FL) (COMPOSE-METHOD-COMBINATION FL))))))
                    641: 
                    642: (DEFUN DESCRIBE-FLAVOR (FLAVOR-NAME &AUX FL)
                    643:   (SETQ FL (IF (SYMBOLP FLAVOR-NAME) (GET-FLAVOR FLAVOR-NAME)
                    644:               FLAVOR-NAME))
                    645:   (CHECK-ARG FLAVOR-NAME (:TYPEP FL 'FLAVOR)
                    646:             "a flavor or the name of one")
                    647:   (FORMAT T "~&Flavor ~S directly depends on flavors: ~:[none~;~1G~{~S~^, ~}~]~%"
                    648:            FLAVOR-NAME (FLAVOR-DEPENDS-ON FL))
                    649:   (AND (FLAVOR-INCLUDES FL)
                    650:        (FORMAT T " and directly includes ~{~S~^, ~}~%" (FLAVOR-INCLUDES FL)))
                    651:   (AND (FLAVOR-DEPENDED-ON-BY FL)
                    652:        (FORMAT T " and is directly depended on by ~{~S~^, ~}~%" (FLAVOR-DEPENDED-ON-BY FL)))
                    653:   (AND (FLAVOR-DEPENDS-ON-ALL FL)      ;If this has been computed, show it
                    654:        (FORMAT T " and directly or indirectly depends on ~{~S~^, ~}~%"
                    655:                 (FLAVOR-DEPENDS-ON-ALL FL)))
                    656:   (AND (FLAVOR-METHOD-HASH-TABLE FL)   ;If has been composed
                    657:        (FORMAT T "Flavor ~S has instance variables ~:S~%"
                    658:                 FLAVOR-NAME (FLAVOR-ALL-INSTANCE-VARIABLES FL)))
                    659:   (COND ((NOT (NULL (FLAVOR-METHOD-TABLE FL)))
                    660:         (FORMAT T "Not counting inherited methods, the methods for ~S are:~%"
                    661:                 FLAVOR-NAME)
                    662:         (DOLIST (M (FLAVOR-METHOD-TABLE FL))
                    663:           (FORMAT T "   ")
                    664:           (DO ((TPL (SUBSET 'METH-DEFINEDP (CDDDR M)) (CDR TPL)))
                    665:             ((NULL TPL))
                    666:             (IF (METH-METHOD-TYPE (CAR TPL))
                    667:                 (FORMAT T "~A " (METH-METHOD-TYPE (CAR TPL))))
                    668:             (FORMAT T "~A" (CAR M))
                    669:             (IF (CDR TPL) (PRINC ", ")))
                    670:           ;; Print the method combination type if there is any.
                    671:           (AND (CADR M)
                    672:                (FORMAT T "    :~A~@[ :~A~]" (CADR M) (CADDR M)))
                    673:           (TERPRI))))
                    674:   (AND (FLAVOR-ALL-INSTANCE-VARIABLES FL)
                    675:        (FORMAT T "Instance variables: ~{~S~^, ~}~%" (FLAVOR-ALL-INSTANCE-VARIABLES FL)))
                    676:   (AND (FLAVOR-GETTABLE-INSTANCE-VARIABLES FL)
                    677:        (FORMAT T "Automatically-generated methods to get instance variables: ~{~S~^, ~}~%"
                    678:                 (FLAVOR-GETTABLE-INSTANCE-VARIABLES FL)))
                    679:   (AND (FLAVOR-SETTABLE-INSTANCE-VARIABLES FL)
                    680:        (FORMAT T "Automatically-generated methods to set instance variables: ~{~S~^, ~}~%"
                    681:                 (FLAVOR-SETTABLE-INSTANCE-VARIABLES FL)))
                    682:   (AND (FLAVOR-INITABLE-INSTANCE-VARIABLES FL)
                    683:        (FORMAT T "Instance variables that may be set by initialization: ~{~S~^, ~}~%"
                    684:                 (MAPCAR #'CDR (FLAVOR-INITABLE-INSTANCE-VARIABLES FL))))
                    685:   (AND (FLAVOR-INIT-KEYWORDS FL)
                    686:        (FORMAT T "Keywords in the :INIT message handled by this flavor: ~{~S~^, ~}~%"
                    687:                 (FLAVOR-INIT-KEYWORDS FL)))
                    688:   (COND ((FLAVOR-PLIST FL)
                    689:         (FORMAT T "Properties:~%")
                    690:         (DO L (CDR (FLAVOR-PLIST FL)) (CDDR L) (NULL L)
                    691:           (FORMAT T "~5X~S:    ~S~%" (CAR L) (CADR L)))))
                    692:   (COND ((NULL (FLAVOR-METHOD-HASH-TABLE FL))
                    693:         (FORMAT T "Flavor ~S does not yet have a method hash table~%" FLAVOR-NAME))
                    694:        (T (FORMAT T "Flavor ~S has method hash table:~%" FLAVOR-NAME)
                    695:           (PRINT (FLAVOR-METHOD-HASH-TABLE FL)))))
                    696: 
                    697: ;; This is the standard way of defining a method of a class,
                    698: ;; so that the code will be compiled.  
                    699: ;; If in place of the lambda-list you have a symbol, and the body
                    700: ;; is null, that symbol is a function which stands in for the method.
                    701: (DEFMACRO DEFMETHOD (SPEC LAMBDA-LIST . BODY)
                    702:   (LET ((CLASS-NAME (CAR SPEC))
                    703:        (FUNCTION-SPEC (CONS ':METHOD SPEC))
                    704:        FUNCTION-NAME)
                    705:     (SETQ FUNCTION-NAME (METHOD-FUNCTION-NAME FUNCTION-SPEC))
                    706:     `(PROGN 'COMPILE
                    707:        (EVAL-WHEN (COMPILE LOAD EVAL)
                    708:          (FLAVOR-NOTICE-METHOD ',FUNCTION-SPEC))
                    709:        ;; At load-time, define the method function
                    710:        ,(COND ((AND (SYMBOLP LAMBDA-LIST) (NOT (NULL LAMBDA-LIST))
                    711:                    (NULL BODY))
                    712:               #-Franz `(FDEFINE ',FUNCTION-SPEC ',LAMBDA-LIST)
                    713:               #+Franz `(DEFUN ,FUNCTION-NAME (OPERATION . ,LAMBDA-LIST)
                    714:                               (,lambda-list (operation . ,lambda-list))))
                    715:              ((GET CLASS-NAME 'FLAVOR)
                    716:               `(DEFUN ,FUNCTION-NAME (OPERATION . ,LAMBDA-LIST)
                    717:                  (DECLARE (SPECIAL SELF .OWN-FLAVOR.
                    718:                                    ,@(FLAVOR-ALL-INSTANCE-VARIABLES
                    719:                                       (GET-FLAVOR CLASS-NAME))))
                    720:                  . ,BODY))
                    721:              (T ;; The non-flavor class system
                    722:                (FERROR () "Old Class system is not SUPPORTED")))
                    723:        ',FUNCTION-SPEC)))
                    724: 
                    725: (DEFUN REMOVE-COLON (SYMBOL)
                    726:   (IF (= (GETCHARN SYMBOL 1) #/:)
                    727:       (CONCAT (SUBSTRING SYMBOL 2))
                    728:       SYMBOL))
                    729: 
                    730: ; This lets you specify code to be wrapped around the invocation of the
                    731: ; various methods for an operation.  For example,
                    732: ; (DEFWRAPPER (FOO-FLAVOR :OPERATION) ((ARG1 ARG2) . BODY)
                    733: ;   `(WITH-FOO-LOCKED (SELF)
                    734: ;      (PRE-FROBULATE SELF ARG1 ARG2)
                    735: ;      ,@BODY
                    736: ;      (POST-FROBULATE SELF ARG2 ARG1)))
                    737: ;Note that the wrapper needs to be defined at both compile and run times
                    738: ;so that compiling combined methods as part of the qfasl file works.
                    739: 
                    740: #+Franz
                    741: (defmacro destructuring-bind (template values . body)
                    742:  `(let ((,template ,values)) . ,body))
                    743: 
                    744: (DEFMACRO DEFWRAPPER
                    745:   ((FLAVOR-NAME OPERATION) (DEFMACRO-LAMBDA . GUTS) &BODY BODY)
                    746:   (LET ((FUNCTION-SPEC `(:METHOD ,FLAVOR-NAME :WRAPPER ,OPERATION))
                    747:        function-name)
                    748:        (setq function-name (method-function-name function-spec))
                    749:        `(PROGN ;; 'COMPILE
                    750:               ;; Unfortunately, in Franz wrappers should not be compiled
                    751:               ;; since the actual definition is needed by macrocall.
                    752:               ;; Macrocall is clearly a crock!
                    753:            ;; The following optimization could go away if defmacro were
                    754:            ;; very smart.
                    755:            ,(IF (AND (SYMBOLP DEFMACRO-LAMBDA)
                    756:                      (EQUAL DEFMACRO-LAMBDA 'IGNORE))
                    757:                 `(DEFMACRO ,function-name (IGNORE . ,GUTS) . ,BODY)
                    758:                 `(DEFMACRO ,function-name (ARGLISTNAME . ,GUTS)
                    759:                    `(DESTRUCTURING-BIND ,',DEFMACRO-LAMBDA (CDR ,ARGLISTNAME)
                    760:                                         ,,@BODY)))
                    761:         (flavor-notice-method ',function-spec))))
                    762: 
                    763: ;This just exists to be called at compile-time from the DEFMETHOD macro,
                    764: ;so that any combined methods generated by COMPILE-FLAVOR-METHODS will
                    765: ;know that this method will be around at run time and should be called.
                    766: (DEFUN FLAVOR-NOTICE-METHOD (FUNCTION-SPEC)
                    767:   (LET ((METH (FLAVOR-METHOD-ENTRY FUNCTION-SPEC NIL T)))
                    768:     (COND ((NOT (EQ (METH-DEFINITION METH)
                    769:                    (METHOD-FUNCTION-NAME FUNCTION-SPEC)))
                    770:           (SETF (METH-DEFINITION METH) (METHOD-FUNCTION-NAME FUNCTION-SPEC))
                    771:           (RECOMPILE-FLAVOR (SECOND FUNCTION-SPEC)
                    772:                             (CAR (LAST FUNCTION-SPEC)))))))
                    773: 
                    774: (DEFUN METHOD-FUNCTION-NAME (FUNCTION-SPEC)
                    775:   (LET ((FLAVOR (SECOND FUNCTION-SPEC))
                    776:        (METHOD-TYPE (THIRD FUNCTION-SPEC))
                    777:        (MESSAGE (FOURTH FUNCTION-SPEC)))
                    778:     (IF (NULL (CDDDR FUNCTION-SPEC))
                    779:        (SETQ MESSAGE (THIRD FUNCTION-SPEC) METHOD-TYPE NIL))
                    780:     (IF (NULL METHOD-TYPE)
                    781:        (INTERN (FORMAT () "~A-~A-method" FLAVOR (REMOVE-COLON MESSAGE)))
                    782:        (INTERN
                    783:         (FORMAT () "~A-~A-~A-method"
                    784:                 FLAVOR (REMOVE-COLON METHOD-TYPE) (REMOVE-COLON MESSAGE))))))
                    785: 
                    786: ;Find or create a method-table entry for the specified method.
                    787: ;DONT-CREATE is NIL if method is to be created if necessary.
                    788: ;      The flavor is "created" too, as an UNDEFINED-FLAVOR property
                    789: ;      of the flavor name, just to record any properties of methods.
                    790: ;COPY-FLAVOR-IF-UNDEFINED-METH says we are going to alter the METH
                    791: ;for compilation if it is not defined, so the flavor should be copied in that case.
                    792: (DEFUN FLAVOR-METHOD-ENTRY (FUNCTION-SPEC DONT-CREATE
                    793:                                &OPTIONAL COPY-FLAVOR-IF-UNDEFINED-METH)
                    794:                                          ;; Huh? Unused! -SMH
                    795:   (LET ((FLAVOR-NAME (SECOND FUNCTION-SPEC))
                    796:        (TYPE (THIRD FUNCTION-SPEC))
                    797:        (MESSAGE (FOURTH FUNCTION-SPEC)))
                    798:     (IF (NULL MESSAGE) (SETQ MESSAGE TYPE TYPE NIL))   ;If no type
                    799:     (IF (OR (NULL MESSAGE) (NEQ (FIRST FUNCTION-SPEC) ':METHOD)
                    800:            (> (LENGTH FUNCTION-SPEC) 4)
                    801:            (NOT (SYMBOLP FLAVOR-NAME)) (NOT (SYMBOLP TYPE))
                    802:            (NOT (SYMBOLP MESSAGE)))
                    803:        (FERROR () "~S is not a valid function-spec" FUNCTION-SPEC))
                    804:     (LET* ((FL (OR (GET-FLAVOR FLAVOR-NAME)
                    805:                   (GET FLAVOR-NAME 'UNDEFINED-FLAVOR)
                    806:                   (AND (NOT DONT-CREATE)
                    807:                        (PUTPROP FLAVOR-NAME
                    808:                                 (MAKE-FLAVOR FLAVOR-NAME FLAVOR-NAME)
                    809:                                 'UNDEFINED-FLAVOR))))
                    810:           (MTE (AND FL (ASSQ MESSAGE (FLAVOR-METHOD-TABLE FL))))
                    811:           (METH (METH-LOOKUP TYPE (CDDDR MTE))))
                    812:       (AND (NULL MTE) (NOT DONT-CREATE)
                    813:           ;; Message not previously known about, put into table
                    814:           FL
                    815:           (PUSH (SETQ MTE (LIST* MESSAGE NIL NIL NIL)) (FLAVOR-METHOD-TABLE FL)))
                    816:       ;; Message known, search for the type entry
                    817:       (COND (METH)     ;Known by flavor
                    818:            (DONT-CREATE NIL)           ;Not to be created
                    819:            ((NULL FL) NIL)     ;Create, but no flavor defined
                    820:            (T ;; Type not known, create a new meth with an unbound definition cell
                    821:             (LET ((METH (LIST FUNCTION-SPEC NIL NIL)))
                    822:               (NULLIFY-METHOD-DEFINITION METH)
                    823:               (PUSH METH (CDDDR MTE))
                    824:               METH))))))
                    825: 
                    826: ;;; See if a certain method exists in a flavor
                    827: (DEFUN FLAVOR-METHOD-EXISTS (FL TYPE OPERATION &AUX MTE)
                    828:   (AND (SETQ MTE (ASSQ OPERATION (FLAVOR-METHOD-TABLE FL)))
                    829:        (LET ((METH (METH-LOOKUP TYPE (CDDDR MTE))))
                    830:         (AND METH (METH-DEFINEDP METH)))))
                    831: 
                    832: ;;; Forcibly remove a method definition from a flavor's method table
                    833: ;;; Syntax is identical to the beginning of a defmethod for the same method.
                    834: (DEFMACRO UNDEFMETHOD (SPEC)
                    835:   `(FUNDEFINE '(:METHOD . ,SPEC)))
                    836: 
                    837: ;Make an object of a particular flavor, taking the init-plist options
                    838: ;as a rest argument and sending the :INIT message if the flavor
                    839: ;handles it.
                    840: (DEFUN MAKE-INSTANCE (FLAVOR-NAME &REST INIT-OPTIONS)
                    841:   (INSTANTIATE-FLAVOR FLAVOR-NAME (CONS 'INSTANCE-OPTIONS INIT-OPTIONS)
                    842:                      'MAYBE))
                    843: 
                    844: (DEFUN FLAVOR-DISPATCH (MESSAGE &REST ARGUMENTS &AUX FUN)
                    845:   (DECLARE (SPECIAL .OWN-FLAVOR.))
                    846:   (SETQ FUN (OR (GETHASH MESSAGE (FLAVOR-METHOD-HASH-TABLE .OWN-FLAVOR.))
                    847:                (FLAVOR-DEFAULT-HANDLER .OWN-FLAVOR.)))
                    848:   (IF (NOT (NULL FUN))
                    849:       (LEXPR-FUNCALL FUN MESSAGE ARGUMENTS)
                    850:       (FLAVOR-UNCLAIMED-MESSAGE MESSAGE ARGUMENTS)))      
                    851: 
                    852: ;; The first six slots are for SELF and .OWN-FLAVOR. The values are in the
                    853: ;; third slot.
                    854: ; SMH@EMS VVV
                    855: ; Perforce, %instance-ref no longer used.
                    856: ;      (DEFSUBST %INSTANCE-REF (INSTANCE INDEX)
                    857: ;        (VREF INSTANCE (+ 9. (* 3 INDEX))))
                    858: ;      (DEFSUBST INSTANCE-FLAVOR (INSTANCE) (VREF INSTANCE 6))
                    859: ; The previous instance-flavor ought always to be good, if inefficient.
                    860: ;      (DEFSUBST INSTANCE-FLAVOR (INSTANCE) (VREF INSTANCE 3))
                    861: ; SMH@EMS ^^^
                    862: 
                    863: ;Make an object of a particular flavor.
                    864: ;If the flavor hasn't been composed yet, must do so now.
                    865: ; Delaying it until the first time it is needed aids initialization,
                    866: ; e.g. up until now we haven't depended on the depended-on flavors being defined yet.
                    867: ;Note that INIT-PLIST can be modified, if the :DEFAULT-INIT-PLIST option was
                    868: ; used or the init methods modify it.
                    869: (DEFUN INSTANTIATE-FLAVOR (FLAVOR-NAME INIT-PLIST
                    870:                           &OPTIONAL SEND-INIT-MESSAGE-P
                    871:                                     RETURN-UNHANDLED-KEYWORDS-P ;as second value
                    872:                           &AUX FL FFL UNHANDLED-KEYWORDS INSTANCE VARS N TEM)
                    873:   (CHECK-ARG FLAVOR-NAME (SETQ FL (GET FLAVOR-NAME 'FLAVOR)) "the name of a flavor")
                    874:   ;; Do any composition (compilation) of combined stuff, if not done already
                    875:   (OR (FLAVOR-DEPENDS-ON-ALL FL) (COMPOSE-FLAVOR-COMBINATION FL))
                    876:   (OR (FLAVOR-METHOD-HASH-TABLE FL) (COMPOSE-METHOD-COMBINATION FL))
                    877:   (SETQ VARS (FLAVOR-ALL-INSTANCE-VARIABLES FL))
                    878: ;; Make the instance object, then fill in its various fields
                    879:   (SETQ INSTANCE
                    880:        (PROGV `(SELF .OWN-FLAVOR. ,@VARS)
                    881:               `(NIL ,FL)
                    882:               (FCLOSURE `(SELF .OWN-FLAVOR. ,@VARS)
                    883:                         #'FLAVOR-DISPATCH)))
                    884:   (LOOP FOR I FROM 0 TO (LENGTH VARS)
                    885:        WITH IVS = (FLAVOR-INSTANCE-VARIABLE-INITIALIZATIONS FL)
                    886:        WHEN (= I (CAAR IVS))
                    887: ; SMH@EMS VVV
                    888: ;      DO (PROGN (SETF (%INSTANCE-REF INSTANCE I)
                    889: ;                      (FAST-EVAL (CADAR IVS)))
                    890: ;                (POP IVS)))
                    891:        DO (PROGN (INT:FCLOSURE-STACK-STUFF (VREF INSTANCE (+ 3 I))
                    892:                                            (FAST-EVAL (CADAR IVS)))
                    893:                  (POP IVS)))
                    894: ; SMH@EMS ^^^
                    895:   (SET-IN-FCLOSURE INSTANCE 'SELF INSTANCE)
                    896:   (LET ((VAR-KEYWORDS (FLAVOR-ALL-INITABLE-INSTANCE-VARIABLES FL))
                    897:        (REMAINING-KEYWORDS (FLAVOR-REMAINING-INIT-KEYWORDS FL)))
                    898:     (COND (VAR-KEYWORDS
                    899:           ;; First, process any user-specified init keywords that
                    900:           ;; set instance variables.  When we process the defaults,
                    901:           ;; we will see that these are already set, and will
                    902:           ;; refrain from evaluating the default forms.  At the same time,
                    903:           ;; we record any init keywords that this flavor doesn't handle.
                    904:           (DO ((PL (CDR INIT-PLIST) (CDDR PL))) ((NULL PL))
                    905:             (COND ((MEMQ (CAR PL) VAR-KEYWORDS)
                    906:                    (SET-IN-FCLOSURE INSTANCE (REMOVE-COLON (CAR PL))
                    907:                                     (CADR PL)))
                    908:                   ((NOT (MEMQ (CAR PL) REMAINING-KEYWORDS))
                    909:                    (PUSH (CAR PL) UNHANDLED-KEYWORDS))))
                    910:           ;; Now stick any default init plist items that aren't handled by 
                    911:           ;; that onto the actual init plist.
                    912:           (DO ((PL (FLAVOR-REMAINING-DEFAULT-PLIST FL) (CDDR PL)))
                    913:               ((NULL PL))
                    914:             (OR (MEMQ-ALTERNATED (CAR PL) (CDR INIT-PLIST))
                    915:                 (PUTPROP INIT-PLIST (FAST-EVAL (CADR PL)) (CAR PL)))))
                    916:          (T
                    917:           ;; Put defaults into the INIT-PLIST
                    918:           (FLAVOR-DEFAULT-INIT-PLIST FLAVOR-NAME INIT-PLIST)
                    919:           ;; For each init keyword, either initialize the corresponding 
                    920:           ;; variable, remember that it will be handled later by an :INIT 
                    921:           ;; method, or give an error for not being handled.
                    922:           (DO L (CDR INIT-PLIST) (CDDR L) (NULL L)
                    923:               (LET ((KEYWORD (CAR L)) (ARG (CADR L)))
                    924:                 (DO ((FFLS (FLAVOR-DEPENDS-ON-ALL FL) (CDR FFLS)))
                    925:                     ((NULL FFLS) (PUSH KEYWORD UNHANDLED-KEYWORDS))
                    926:                   (SETQ FFL (GET (CAR FFLS) 'FLAVOR))
                    927:                   (COND ((SETQ TEM (ASSQ KEYWORD (FLAVOR-INITABLE-INSTANCE-VARIABLES FFL)))
                    928:                          (SET-IN-FCLOSURE INSTANCE (REMOVE-COLON KEYWORD)
                    929:                                           ARG)
                    930:                          (RETURN))
                    931:                         ((MEMQ KEYWORD (FLAVOR-INIT-KEYWORDS FFL))
                    932:                          (RETURN)))))))))
                    933:   ;; Complain if any keywords weren't handled, unless our caller
                    934:   ;; said it wanted to take care of this.
                    935:   (AND (NOT RETURN-UNHANDLED-KEYWORDS-P)
                    936:        UNHANDLED-KEYWORDS
                    937:        (FERROR () "Flavor ~S does not handle the init keyword~P ~{~S~^, ~}"
                    938:               FLAVOR-NAME
                    939:               (LENGTH UNHANDLED-KEYWORDS)
                    940:               UNHANDLED-KEYWORDS))
                    941:   (AND (EQ SEND-INIT-MESSAGE-P 'MAYBE)
                    942:        (NOT (GET-HANDLER-FOR INSTANCE ':INIT))
                    943:        (SETQ SEND-INIT-MESSAGE-P NIL))
                    944:   (AND SEND-INIT-MESSAGE-P
                    945:        (SEND INSTANCE ':INIT INIT-PLIST))
                    946:   (VALUES INSTANCE UNHANDLED-KEYWORDS))
                    947: 
                    948: (DEFUN MEMQ-ALTERNATED (ELT LIST)
                    949:   (DO ((L LIST (CDDR L))) ((NULL L) NIL)
                    950:     (IF (EQ (CAR L) ELT) (RETURN L))))
                    951: 
                    952: (DEFUN FAST-EVAL (EXP)
                    953:   (COND ((OR (NUMBERP EXP) (STRINGP EXP)
                    954:             (MEMQ EXP '(T NIL)))
                    955:         EXP)
                    956:        ((SYMBOLP EXP) (SYMEVAL EXP))
                    957:        ((AND (LISTP EXP) (EQ (CAR EXP) 'QUOTE))
                    958:         (CADR EXP))
                    959:        (T (EVAL EXP))))
                    960: 
                    961: (DEFUN FLAVOR-DEFAULT-INIT-PLIST (FLAVOR-NAME
                    962:                                  &OPTIONAL (INIT-PLIST (NCONS NIL))
                    963:                                  &AUX FL)
                    964:   (CHECK-ARG FLAVOR-NAME (SETQ FL (GET FLAVOR-NAME 'FLAVOR))
                    965:             "the name of a flavor")
                    966:   ;; Do any composition (compilation) of combined stuff, if not done already
                    967:   (OR (FLAVOR-DEPENDS-ON-ALL FL) (COMPOSE-FLAVOR-COMBINATION FL))
                    968:   (DOLIST (FFL (FLAVOR-DEPENDS-ON-ALL FL))
                    969:     (SETQ FFL (GET FFL 'FLAVOR))
                    970:     (DO L (GET (FLAVOR-PLIST FFL) ':DEFAULT-INIT-PLIST) (CDDR L) (NULL L)
                    971:       (DO ((M (CDR INIT-PLIST) (CDDR M)))
                    972:          ((NULL M) (PUTPROP INIT-PLIST (EVAL (CADR L)) (CAR L)))
                    973:        (AND (EQ (CAR M) (CAR L)) (RETURN)))))
                    974:   INIT-PLIST)
                    975: 
                    976: ;Returns non-NIL if the flavor allows the specified keyword in its init-plist,
                    977: ;NIL if it doesn't.  The return value is the name of the component flavor
                    978: ;that actually handles it.
                    979: (DEFUN FLAVOR-ALLOWS-INIT-KEYWORD-P (FLAVOR-NAME KEYWORD)
                    980:   (MAP-OVER-COMPONENT-FLAVORS 0 T T
                    981:       #'(LAMBDA (FL IGNORE KEYWORD)
                    982:          (AND (OR (ASSQ KEYWORD (FLAVOR-INITABLE-INSTANCE-VARIABLES FL))
                    983:                   (MEMQ KEYWORD (FLAVOR-INIT-KEYWORDS FL)))
                    984:               (FLAVOR-NAME FL)))
                    985:       FLAVOR-NAME NIL KEYWORD))
                    986: 
                    987: ;;; Given the name of a flavor, return a list of all of the symbols that
                    988: ;;; are valid init-options for the flavor, sorted alphabetically.
                    989: ;;; Primary for inquiries by humans.
                    990: (DEFUN FLAVOR-ALLOWED-INIT-KEYWORDS (FLAVOR-NAME)
                    991:   (LET ((INIT-KEYWORDS NIL))
                    992:     (DECLARE (SPECIAL INIT-KEYWORDS))
                    993:     (MAP-OVER-COMPONENT-FLAVORS 0 T NIL
                    994:        #'(LAMBDA (FLAVOR IGNORE)
                    995:            (DECLARE (SPECIAL INIT-KEYWORDS))
                    996:            (SETQ INIT-KEYWORDS
                    997:                  (NCONC (MAPCAR #'(LAMBDA (KWD)
                    998:                                     (IF (LISTP KWD) (CAR KWD) KWD))
                    999:                                 (FLAVOR-LOCAL-INIT-KEYWORDS FLAVOR))
                   1000:                         INIT-KEYWORDS)))
                   1001:        FLAVOR-NAME NIL)
                   1002:     (SORT (ELIMINATE-DUPLICATES INIT-KEYWORDS) #'ALPHALESSP)))
                   1003: 
                   1004: (DEFUN FLAVOR-LOCAL-INIT-KEYWORDS (FLAVOR)
                   1005:   (APPEND (FLAVOR-INITABLE-INSTANCE-VARIABLES FLAVOR)
                   1006:          (FLAVOR-INIT-KEYWORDS FLAVOR)))
                   1007: 
                   1008: (DEFUN ELIMINATE-DUPLICATES (LIST &AUX L)
                   1009:   (DOLIST (E LIST) (OR (MEMQ E L) (PUSH E L)))
                   1010:   L)
                   1011: 
                   1012: ; Function to map over all components of a specified flavor.  We must do the
                   1013: ;  DEPENDS-ON's to all levels first, then the INCLUDES's at all levels and
                   1014: ;  what they depend on.
                   1015: ; Note that it does the specified flavor itself as well as all its components.
                   1016: ; Note well: if there are included flavors, this does not do them in the
                   1017: ;  right order.  Also note well: if there are multiple paths to a component,
                   1018: ;  it will be done more than once.
                   1019: ; RECURSION-STATE is 0 except when recursively calling itself.
                   1020: ; ERROR-P is T if not-yet-defflavored flavors are to be complained about,
                   1021: ;  NIL if they are to be ignored.  This exists to get rid of certain
                   1022: ;  bootstrapping problems.
                   1023: ; RETURN-FIRST-NON-NIL is T if the iteration should terminate as soon
                   1024: ;  as FUNCTION returns a non-null result.
                   1025: ; At each stage FUNCTION is applied to the flavor (not the name), the
                   1026: ;  STATE, and any ARGS.  STATE is updated to whatever the function returns.
                   1027: ; The final STATE is the final result of this function.
                   1028: ; RECURSION-STATE is:
                   1029: ;  0   top-level
                   1030: ;  1   first-pass over just depends-on's
                   1031: ;  6   second-pass, this flavor reached via depends-on's so don't do it again
                   1032: ;  2   second-pass, this flavor reached via includes's so do it.
                   1033: (DEFVAR SOME-COMPONENT-UNDEFINED NIL)   ;If we find an undefined component, we put its name here.
                   1034: 
                   1035: (DEFUN MAP-OVER-COMPONENT-FLAVORS (RECURSION-STATE ERROR-P
                   1036:                                   RETURN-FIRST-NON-NIL FUNCTION FLAVOR-NAME
                   1037:                                   STATE &REST ARGS)
                   1038:   (PROG (FL)
                   1039:    (*CATCH 'MAP-OVER-COMPONENT-FLAVORS
                   1040:     (COND ((OR ERROR-P (GET-FLAVOR FLAVOR-NAME))
                   1041:           (CHECK-ARG FLAVOR-NAME (SETQ FL (GET-FLAVOR FLAVOR-NAME))
                   1042:                      "a defined flavor")
                   1043:           ;; First do this flavor, unless this is the second pass and it shouldn't be done
                   1044:           (OR (BIT-TEST 4 RECURSION-STATE)
                   1045:               (SETQ STATE (LEXPR-FUNCALL FUNCTION FL STATE ARGS)))
                   1046:           ;; After each call to the function, see if we're supposed to be done now
                   1047:           (AND RETURN-FIRST-NON-NIL (NOT (NULL STATE))
                   1048:                (*THROW 'MAP-OVER-COMPONENT-FLAVORS NIL))
                   1049:           ;; Now do the depends-on's.
                   1050:           (DOLIST (COMPONENT-FLAVOR (FLAVOR-DEPENDS-ON FL))
                   1051:             (SETQ STATE (LEXPR-FUNCALL #'MAP-OVER-COMPONENT-FLAVORS
                   1052:                                            (IF (ZEROP RECURSION-STATE) 1 RECURSION-STATE)
                   1053:                                            ERROR-P RETURN-FIRST-NON-NIL
                   1054:                                            FUNCTION COMPONENT-FLAVOR STATE ARGS))
                   1055:             (AND RETURN-FIRST-NON-NIL (NOT (NULL STATE))
                   1056:                  (*THROW 'MAP-OVER-COMPONENT-FLAVORS NIL)))
                   1057:           ;; Unless this is the first pass, do the includes.
                   1058:           (OR (BIT-TEST 1 RECURSION-STATE)
                   1059:               (DOLIST (COMPONENT-FLAVOR (FLAVOR-INCLUDES FL))
                   1060:                 (SETQ STATE (LEXPR-FUNCALL #'MAP-OVER-COMPONENT-FLAVORS
                   1061:                                                2 ERROR-P RETURN-FIRST-NON-NIL
                   1062:                                                FUNCTION COMPONENT-FLAVOR STATE ARGS))
                   1063:                 (AND RETURN-FIRST-NON-NIL (NOT (NULL STATE))
                   1064:                      (*THROW 'MAP-OVER-COMPONENT-FLAVORS NIL))))
                   1065:           ;; If this is the top-level, run the second pass on its depends-on's
                   1066:           ;; which doesn't do them but does do what they include.
                   1067:           (OR (NOT (ZEROP RECURSION-STATE))
                   1068:               (DOLIST (COMPONENT-FLAVOR (FLAVOR-DEPENDS-ON FL))
                   1069:                 (SETQ STATE (LEXPR-FUNCALL #'MAP-OVER-COMPONENT-FLAVORS
                   1070:                                            6 ERROR-P RETURN-FIRST-NON-NIL
                   1071:                                            FUNCTION COMPONENT-FLAVOR STATE ARGS))
                   1072:                 (AND RETURN-FIRST-NON-NIL (NOT (NULL STATE))
                   1073:                      (*THROW 'MAP-OVER-COMPONENT-FLAVORS NIL)))))
                   1074:          ((NULL SOME-COMPONENT-UNDEFINED)
                   1075:           (SETQ SOME-COMPONENT-UNDEFINED FLAVOR-NAME)))))
                   1076:   STATE)
                   1077: 
                   1078: ;Call this when a flavor has been changed, it updates that flavor's compiled
                   1079: ; information and that of any that depend on it.
                   1080: ;If a compilation is in progress the compilations performed
                   1081: ; will get output as part of that compilation.
                   1082: ;SINGLE-OPERATION is NIL to do all operations, or the name of an operation
                   1083: ; which needs incremental compilation.
                   1084: ;USE-OLD-COMBINED-METHODS can be NIL to force regeneration of all combined methods.
                   1085: ; This is used if a wrapper has changed or there was a bug in the method-combining routine.
                   1086: ;DO-DEPENDENTS controls whether flavors that depend on this one are also compiled.
                   1087: (DEFUN RECOMPILE-FLAVOR (FLAVOR-NAME
                   1088:                         &OPTIONAL (SINGLE-OPERATION NIL) (*USE-OLD-COMBINED-METHODS* T)
                   1089:                                   (DO-DEPENDENTS T)
                   1090:                         &AUX FL)
                   1091:   (CHECK-ARG FLAVOR-NAME (SETQ FL (GET FLAVOR-NAME 'FLAVOR)) "the name of a flavor")
                   1092:   ;; Only update the method combination if it has been done before, else 
                   1093:   ;; doesn't matter
                   1094:   (COND ((FLAVOR-METHOD-HASH-TABLE FL)
                   1095:         (OR (FLAVOR-DEPENDS-ON-ALL FL)
                   1096:             (COMPOSE-FLAVOR-COMBINATION FL))
                   1097:         (COMPOSE-METHOD-COMBINATION FL SINGLE-OPERATION)))
                   1098:   (IF DO-DEPENDENTS
                   1099:       (LET ((FDEFINE-FILE-PATHNAME NIL))       ;Don't give warnings for combined methods
                   1100:        (DOLIST (FN (FLAVOR-DEPENDED-ON-BY-ALL FL))
                   1101:          (IF (FLAVOR-METHOD-HASH-TABLE (GET FN 'FLAVOR))
                   1102:              (RECOMPILE-FLAVOR FN SINGLE-OPERATION *USE-OLD-COMBINED-METHODS* NIL))))))
                   1103: 
                   1104: ;Make a list of all flavors that depend on this one, not including this flavor itself.
                   1105: ;This is a list of the names, not the defstructs.
                   1106: (DEFUN FLAVOR-DEPENDED-ON-BY-ALL (FL &OPTIONAL (LIST-SO-FAR NIL) &AUX FFL)
                   1107:   (DOLIST (FN (FLAVOR-DEPENDED-ON-BY FL))
                   1108:     (OR (MEMQ FN LIST-SO-FAR)
                   1109:        (NOT (SETQ FFL (GET FN 'FLAVOR)))
                   1110:        (SETQ LIST-SO-FAR (FLAVOR-DEPENDED-ON-BY-ALL FFL (CONS FN LIST-SO-FAR)))))
                   1111:   LIST-SO-FAR)
                   1112: 
                   1113: ;This function takes care of flavor-combination.  It sets up the list
                   1114: ;of all component flavors, in appropriate order, and the list of all
                   1115: ;instance variables.  It generally needs to be called only once for a
                   1116: ;flavor, and must be called before method-combination can be dealt with.
                   1117: (DEFVAR FLAVORS-BEING-COMPOSED NIL)
                   1118: 
                   1119: (DEFUN COMPOSE-FLAVOR-COMBINATION (FL &AUX FLS VARS ORDS REQS SIZE
                   1120:                                   (SOME-COMPONENT-UNDEFINED NIL)
                   1121:                                   (FLAVORS-BEING-COMPOSED
                   1122:                                     (CONS FL FLAVORS-BEING-COMPOSED)))
                   1123:   ;; Make list of all component flavors' names.
                   1124:   ;; This list is in outermost-first order.
                   1125:   ;; Would be nice for this not to have to search to all levels, but for
                   1126:   ;; the moment that is hard, so I won't do it.
                   1127:   ;; Included-flavors are hairy: if not otherwise in the list of components, they
                   1128:   ;; are stuck in after the rightmost component that includes them, along with
                   1129:   ;; any components of their own not otherwise in the list.
                   1130:   (SETQ FLS (COPYLIST (COMPOSE-FLAVOR-INCLUSION (FLAVOR-NAME FL) T)))
                   1131:   ;; Don't mark this flavor as "composed" if there were errors.
                   1132:   (OR SOME-COMPONENT-UNDEFINED
                   1133:       (SETF (FLAVOR-DEPENDS-ON-ALL FL) FLS))
                   1134:   ;; Vanilla-flavor may have been put in by magic, so maintain the dependencies
                   1135:   ;; in case new methods get added to it later.
                   1136:   (LET ((VAN (GET-FLAVOR 'SI:VANILLA-FLAVOR))
                   1137:        (FLAV (FLAVOR-NAME FL)))
                   1138:     (AND (NOT (NULL VAN))
                   1139:         (NEQ FLAV 'SI:VANILLA-FLAVOR)
                   1140:         (MEMQ 'SI:VANILLA-FLAVOR FLS)
                   1141:         (NOT (MEMQ FLAV (FLAVOR-DEPENDED-ON-BY VAN)))
                   1142:         (PUSH FLAV (FLAVOR-DEPENDED-ON-BY VAN))))
                   1143:   ;; Compute what the instance variables will be, and in what order.
                   1144:   ;; Also collect the required but not present instance variables, which go onto the
                   1145:   ;; ADDITIONAL-INSTANCE-VARIABLES property.  The instance variables of the
                   1146:   ;; :REQUIRED-FLAVORS work the same way.  Such instance variables are ok
                   1147:   ;; for our methods to access.
                   1148:   (DOLIST (F FLS)
                   1149:     (SETQ F (GET-FLAVOR F))
                   1150:     (DOLIST (V (FLAVOR-LOCAL-INSTANCE-VARIABLES F))
                   1151:       (OR (ATOM V) (SETQ V (CAR V)))
                   1152:       (OR (MEMQ V VARS) (PUSH V VARS)))
                   1153:     (SETQ REQS (UNION REQS
                   1154:                      (GET (FLAVOR-PLIST F) ':REQUIRED-INSTANCE-VARIABLES)))
                   1155:     ;; Any variables our required flavors have or require, we require.
                   1156:     (DOLIST (FF (GET (FLAVOR-PLIST F) ':REQUIRED-FLAVORS))
                   1157:       (COND ((AND (NOT (MEMQ FF FLS))
                   1158:                  (SETQ FF (GET-FLAVOR FF))
                   1159:                  (NOT (MEMQ FF (CDR FLAVORS-BEING-COMPOSED))))
                   1160:             (OR (FLAVOR-DEPENDS-ON-ALL FF) (COMPOSE-FLAVOR-COMBINATION FF))
                   1161:             (SETQ REQS
                   1162:                   (UNION REQS (FLAVOR-ALL-INSTANCE-VARIABLES FF)
                   1163:                          (GET (FLAVOR-PLIST FF) 'ADDITIONAL-INSTANCE-VARIABLES))))))
                   1164:     (LET ((ORD (GET (FLAVOR-PLIST F) ':ORDERED-INSTANCE-VARIABLES)))
                   1165:       ;; Merge into existing order requirement.  Shorter of the two must be
                   1166:       ;; a prefix of the longer, and we take the longer.
                   1167:       (DO ((L1 ORD (CDR L1))
                   1168:           (L2 ORDS (CDR L2)))
                   1169:          (NIL)
                   1170:        (COND ((NULL L1) (RETURN NIL))
                   1171:              ((NULL L2) (RETURN (SETQ ORDS ORD)))
                   1172:              ((NEQ (CAR L1) (CAR L2))
                   1173:               (FERROR () ":ORDERED-INSTANCE-VARIABLES conflict, ~S vs ~S"
                   1174:                           (CAR L1) (CAR L2)))))))
                   1175:   ;; Must not merge this with the previous loop,
                   1176:   ;; to avoid altering order of instance variables
                   1177:   ;; if a DEFFLAVOR is redone.
                   1178:   (DOLIST (F FLS)
                   1179:     (SETQ F (GET-FLAVOR F)))
                   1180:   ;; This NREVERSE makes it compatible with the old code.  There is no other reason for it.
                   1181:   (SETQ VARS (NREVERSE VARS))
                   1182:   ;; Apply ordering requirement by moving those variables to the front.
                   1183:   (DOLIST (V ORDS)
                   1184:     (OR (MEMQ V VARS)
                   1185:        (FERROR () "Flavor ~S lacks instance variable ~S which has an order requirement"
                   1186:                (FLAVOR-NAME FL) V))
                   1187:     (SETQ VARS (DELQ V VARS)))
                   1188:   (SETQ VARS (APPEND ORDS VARS))
                   1189:   (SETF (FLAVOR-ALL-INSTANCE-VARIABLES FL) (COPYLIST VARS))
                   1190:   ;; If there are any instance variables required but not present, save them
                   1191:   ;; so that they can be declared special in methods.
                   1192:   (DOLIST (V VARS)
                   1193:     (SETQ REQS (DELQ V REQS)))
                   1194:   (AND REQS (PUTPROP (FLAVOR-PLIST FL)
                   1195:                     (COPYLIST REQS)
                   1196:                     'ADDITIONAL-INSTANCE-VARIABLES))
                   1197:   NIL)
                   1198: 
                   1199: (DEFUN COMPOSE-FLAVOR-INCLUSION (FLAVOR ERROR-P)
                   1200:   (MULTIPLE-VALUE-BIND (FLS ADDITIONS) (COMPOSE-FLAVOR-INCLUSION-1 FLAVOR NIL ERROR-P)
                   1201:     ;; The new additions may themselves imply more components
                   1202:     (DO L ADDITIONS (CDR L) (NULL L)
                   1203:       (LET ((MORE-FLS (COMPOSE-FLAVOR-INCLUSION-1 (CAR L) FLS ERROR-P)))
                   1204:        (DOLIST (F MORE-FLS)
                   1205:          ;; This hair inserts F before (after) the thing that indirectly included it
                   1206:          ;; and then puts that next on ADDITIONS so it gets composed also
                   1207:          (LET ((LL (MEMQ (CAR L) FLS)))
                   1208:            (RPLACA (RPLACD LL (CONS (CAR LL) (CDR LL))) F)
                   1209:            (RPLACD L (CONS F (CDR L)))))))
                   1210:     ;; Now attach vanilla-flavor if desired
                   1211:     (OR (LOOP FOR FLAVOR IN FLS
                   1212:              THEREIS (GET (FLAVOR-PLIST (GET-FLAVOR FLAVOR))
                   1213:                           ':NO-VANILLA-FLAVOR))
                   1214:        (PUSH 'SI:VANILLA-FLAVOR FLS))
                   1215:     (NREVERSE FLS)))
                   1216: 
                   1217: (local-declare ((special other-components))
                   1218: (DEFUN COMPOSE-FLAVOR-INCLUSION-1 (FLAVOR OTHER-COMPONENTS ERROR-P)
                   1219:   ;; First, make a backwards list of all the normal (non-included) components
                   1220:   (LET ((FLS (MAP-OVER-COMPONENT-FLAVORS 1 ERROR-P NIL
                   1221:               #'(LAMBDA (FL LIST)
                   1222:                   (SETQ FL (FLAVOR-NAME FL))
                   1223:                   (OR (MEMQ FL LIST)
                   1224:                       (MEMQ FL OTHER-COMPONENTS)
                   1225:                       (PUSH FL LIST))
                   1226:                   LIST)
                   1227:               FLAVOR NIL))
                   1228:        (ADDITIONS NIL))
                   1229:     ;; If there are any inclusions that aren't in the list, plug
                   1230:     ;; them in right after (before in backwards list) their last (first) includer
                   1231:     (DO L FLS (CDR L) (NULL L)
                   1232:       (DOLIST (FL (FLAVOR-INCLUDES (GET-FLAVOR (CAR L))))
                   1233:        (OR (MEMQ FL FLS)
                   1234:            (MEMQ FL OTHER-COMPONENTS)
                   1235:            (PUSH (CAR (RPLACA (RPLACD L (CONS (CAR L) (CDR L))) FL)) ADDITIONS))))
                   1236:     (OR (MEMQ FLAVOR FLS)
                   1237:        (SETQ FLS (NCONC FLS
                   1238:                         (NREVERSE
                   1239:                           (LOOP FOR FL IN (FLAVOR-INCLUDES (GET-FLAVOR FLAVOR))
                   1240:                                 UNLESS (OR (MEMQ FL FLS) (MEMQ FL OTHER-COMPONENTS))
                   1241:                                   COLLECT FL
                   1242:                                   AND DO (PUSH FL ADDITIONS))))))
                   1243:     (VALUES FLS ADDITIONS))))
                   1244: 
                   1245: ;Once the flavor-combination stuff has been done, do the method-combination stuff.
                   1246: ;The above function usually only gets called once, but this function gets called
                   1247: ;when a new method is added.
                   1248: ;Specify SINGLE-OPERATION to do this for just one operation, for incremental update.
                   1249: ;NOTE WELL: If a meth is in the method-table at all, it is considered to be defined
                   1250: ; for purposes of compose-method-combination.  Thus merely putprop'ing a method,
                   1251: ; or calling flavor-notice-method, will make the flavor think that method exists
                   1252: ; when it is next composed.  This is necessary to make compile-flavor-methods work.
                   1253: ; (Putprop must create the meth because loading does putprop before fdefine.)
                   1254: (DEFUN COMPOSE-METHOD-COMBINATION (FL &OPTIONAL (SINGLE-OPERATION NIL)
                   1255:                                   &AUX TEM MAGIC-LIST ORDER DEF HT
                   1256:                                        MSG ELEM HANDLERS FFL PL)
                   1257:   ;; If we are doing wholesale method composition,
                   1258:   ;; compose the flavor bindings list also.
                   1259:   ;; This way it is done often enough, but not at every defmethod.
                   1260:   (IF (NOT SINGLE-OPERATION)
                   1261:       (COMPOSE-FLAVOR-INITIALIZATIONS FL))
                   1262:   ;; Look through all the flavors depended upon and collect the following:
                   1263:   ;; A list of all the operations handled and all the methods for each, called MAGIC-LIST.
                   1264:   ;; The default handler for unknown operations.
                   1265:   ;; The declared order of entries in the select-method alist.
                   1266:   ;; Also generate any automatically-created methods not already present.
                   1267:   ;; MAGIC-LIST is roughly the same format as the flavor-method-table, see its comments.
                   1268:   ;; Each magic-list entry is (message comb-type comb-order (type function-spec...)...)
                   1269:   (DO ((FFLS (FLAVOR-DEPENDS-ON-ALL FL) (CDR FFLS)))
                   1270:       ((NULL FFLS))
                   1271:     (SETQ FFL (GET-FLAVOR (CAR FFLS))
                   1272:          PL (FLAVOR-PLIST FFL))
                   1273:     (COND ((NOT SINGLE-OPERATION)
                   1274:           (AND (SETQ TEM (GET PL ':SELECT-METHOD-ORDER))
                   1275:                (SETQ ORDER (NCONC ORDER (COPYLIST TEM))))))
                   1276:     ;; Add data from flavor method-table to magic-list
                   1277:     ;; But skip over combined methods, they are not relevant here
                   1278:     (DOLIST (MTE (FLAVOR-METHOD-TABLE FFL))
                   1279:       (SETQ MSG (CAR MTE)) 
                   1280:      (COND ((OR (NOT SINGLE-OPERATION) (EQ MSG SINGLE-OPERATION))
                   1281:             ;; Well, we're supposed to concern ourselves with this operation
                   1282:             (SETQ ELEM (ASSQ MSG MAGIC-LIST))  ;What we already know about it
                   1283:             (COND ((DOLIST (METH (CDDDR MTE))
                   1284:                      (OR (EQ (METH-METHOD-TYPE METH) ':COMBINED)
                   1285:                          (NOT (METH-DEFINEDP METH))
                   1286:                          (RETURN T)))
                   1287:                    ;; OK, this flavor really contributes to handling this operation
                   1288:                   (OR ELEM (PUSH (SETQ ELEM (LIST* MSG NIL NIL NIL)) MAGIC-LIST))
                   1289:                    ;; For each non-combined method for this operation, add it to the front
                   1290:                    ;; of the magic-list element, thus they are in base-flavor-first order.
                   1291:                    (DOLIST (METH (CDDDR MTE))
                   1292:                      (LET ((TYPE (METH-METHOD-TYPE METH)))
                   1293:                        (COND ((EQ TYPE ':COMBINED))
                   1294:                              ((NOT (METH-DEFINEDP METH)))
                   1295:                              ((NOT (SETQ TEM (ASSQ TYPE (CDDDR ELEM))))
                   1296:                               (PUSH (LIST TYPE (METH-FUNCTION-SPEC METH)) (CDDDR ELEM)))
                   1297:                              ;; Don't let the same method get in twice (how could it?)
                   1298:                              ((NOT (MEMQ (METH-FUNCTION-SPEC METH) (CDR TEM)))
                   1299:                               (PUSH (METH-FUNCTION-SPEC METH) (CDR TEM))))))))
                   1300:             ;; Pick up method-combination declarations
                   1301:             (AND (CADR MTE) (CADR ELEM)        ;If both specify combination-type, check
                   1302:                  (OR (NEQ (CADR MTE) (CADR ELEM)) (NEQ (CADDR MTE) (CADDR ELEM)))
                   1303:                  (FERROR ()
                   1304:                      "Method-combination mismatch ~S-~S vs. ~S-~S, check your DEFFLAVOR's"
                   1305:                      (CADR MTE) (CADDR MTE) (CADR ELEM) (CADDR ELEM)))
                   1306:             (COND ((CADR MTE)                  ;Save combination-type when specified
                   1307:                    (OR ELEM (PUSH (SETQ ELEM (LIST* MSG NIL NIL NIL)) MAGIC-LIST))
                   1308:                    (SETF (CADR ELEM) (CADR MTE))
                   1309:                    (SETF (CADDR ELEM) (CADDR MTE)))) ))))
                   1310:   ;; This NREVERSE tends to put base-flavor methods last
                   1311:   (SETQ MAGIC-LIST (NREVERSE MAGIC-LIST))
                   1312:   ;; Re-order the magic-list according to any declared required order
                   1313:   (DOLIST (MSG (NREVERSE ORDER))
                   1314:     (AND (SETQ TEM (ASSQ MSG MAGIC-LIST))
                   1315:         (SETQ MAGIC-LIST (CONS TEM (DELQ TEM MAGIC-LIST 1)))))
                   1316:   ;; Map over the magic-list.  For each entry call the appropriate 
                   1317:   ;; method-combining routine, which will return a function spec for 
                   1318:   ;; the handler to use for this operation.
                   1319:   (DOLIST (MTE MAGIC-LIST)
                   1320:     ;; Punt if there are no methods at all (just a method-combination declaration)
                   1321:     (COND ((CDDDR MTE)
                   1322:           ;; Process the :DEFAULT methods; if there are any untyped methods the
                   1323:           ;; default methods go away, otherwise they become untyped methods.
                   1324:           (AND (SETQ TEM (ASSQ ':DEFAULT (CDDDR MTE)))
                   1325:                (IF (ASSQ NIL (CDDDR MTE))
                   1326:                    (SETF (CDDDR MTE) (DELQ TEM (CDDDR MTE)))
                   1327:                    (RPLACA TEM NIL)))
                   1328:           (OR (SETQ TEM (GET (OR (CADR MTE) ':DAEMON) 'METHOD-COMBINATION))
                   1329:               (FERROR () "~S unknown method combination type for ~S operation"
                   1330:                           (CADR MTE) (CAR MTE)))
                   1331:           (PUSH (FUNCALL TEM FL MTE) HANDLERS))
                   1332:          (T (SETQ MAGIC-LIST (DELQ MTE MAGIC-LIST 1)))))
                   1333:   ;; Get back into declared order.  We now have a list of function specs for handlers.
                   1334:   (SETQ HANDLERS (NREVERSE HANDLERS))
                   1335:   (COND (SINGLE-OPERATION
                   1336:          ;; If doing SINGLE-OPERATION, put it into the hash table.
                   1337:          ;; If the operation is becoming defined and wasn't, or vice versa,
                   1338:          ;; must recompute the which-operations list.
                   1339:          (OR (COND ((NULL HANDLERS)            ;Deleting method
                   1340:                     (NOT (REMHASH SINGLE-OPERATION
                   1341:                                   (FLAVOR-METHOD-HASH-TABLE FL))))
                   1342:                    (T
                   1343:                     (MULTIPLE-VALUE-BIND (NIL PREVIOUSLY-PRESENT)
                   1344:                       (SWAPHASH SINGLE-OPERATION
                   1345:                                 (SETQ DEF (METHOD-FUNCTION-NAME
                   1346:                                            (CAR HANDLERS)))
                   1347:                                 (FLAVOR-METHOD-HASH-TABLE FL))
                   1348:                       PREVIOUSLY-PRESENT)))
                   1349:              (SETF (FLAVOR-WHICH-OPERATIONS FL) NIL)))
                   1350:        ;; Working on all operations at once.
                   1351:        (T
                   1352:         (SETQ HT (MAKE-HASH-TABLE
                   1353:                   ':SIZE (FIX (TIMES 1.5 (LENGTH MAGIC-LIST)))))
                   1354:         ;; If flavor currently has no hash table, it can't hurt to set 
                   1355:         ;; it early
                   1356:         (OR (FLAVOR-METHOD-HASH-TABLE FL)
                   1357:             (SETF (FLAVOR-METHOD-HASH-TABLE FL) HT))
                   1358:         (DO ((HANDLERS HANDLERS (CDR HANDLERS))
                   1359:              (ML MAGIC-LIST (CDR ML)))
                   1360:           ((NULL ML))
                   1361:           (PUTHASH (CAAR ML) (SETQ DEF (METHOD-FUNCTION-NAME (CAR HANDLERS)))
                   1362:                    HT)
                   1363:           (SETF (FLAVOR-METHOD-HASH-TABLE FL) HT)
                   1364:           (SETF (FLAVOR-WHICH-OPERATIONS FL) NIL))     ;This will have to be recomputed
                   1365:         ;; Make sure that the required variables and methods are present.
                   1366:         (VERIFY-REQUIRED-FLAVORS-METHODS-AND-IVARS FL MAGIC-LIST)))
                   1367:   NIL)
                   1368: 
                   1369: (DEFUN VERIFY-REQUIRED-FLAVORS-METHODS-AND-IVARS (FL MAGIC-LIST)
                   1370:   (DO ((FFLS (FLAVOR-DEPENDS-ON-ALL FL) (CDR FFLS))
                   1371:        (MISSING-METHODS NIL)
                   1372:        (MISSING-INSTANCE-VARIABLES NIL)
                   1373:        (MISSING-FLAVORS NIL)
                   1374:        (REQUIRING-FLAVOR-ALIST NIL))
                   1375:       ((NULL FFLS)
                   1376:        (AND (OR MISSING-INSTANCE-VARIABLES MISSING-METHODS MISSING-FLAVORS)
                   1377:            (FERROR () "Flavor ~S is missing ~
                   1378:                                ~:[~2*~;instance variable~P ~{~S~^, ~} ~]~
                   1379:                                ~:[~3*~;~:[~;and ~]method~P ~{~S~^, ~}~]~
                   1380:                                ~:[~3*~;~:[~;and ~]component flavor~P ~{~S~^, ~}~]
                   1381: Requiring Flavor alist: ~S"
                   1382:                    (FLAVOR-NAME FL)
                   1383:                    MISSING-INSTANCE-VARIABLES
                   1384:                    (LENGTH MISSING-INSTANCE-VARIABLES)
                   1385:                    MISSING-INSTANCE-VARIABLES
                   1386:                    MISSING-METHODS
                   1387:                    MISSING-INSTANCE-VARIABLES
                   1388:                    (LENGTH MISSING-METHODS)
                   1389:                    MISSING-METHODS
                   1390:                    MISSING-FLAVORS
                   1391:                    (OR MISSING-INSTANCE-VARIABLES MISSING-METHODS)
                   1392:                    (LENGTH MISSING-FLAVORS)
                   1393:                    MISSING-FLAVORS
                   1394:                    REQUIRING-FLAVOR-ALIST)))
                   1395:     (LET ((PL (FLAVOR-PLIST (GET (CAR FFLS) 'FLAVOR))))
                   1396:       (DOLIST (REQM (GET PL ':REQUIRED-METHODS))
                   1397:        (OR (ASSQ REQM MAGIC-LIST)
                   1398:            (MEMQ REQM MISSING-METHODS)
                   1399:            (PROGN (PUSH REQM MISSING-METHODS)
                   1400:                   (PUSH (CONS (FIRST FFLS) REQM) REQUIRING-FLAVOR-ALIST))))
                   1401:       (DOLIST (REQV (GET PL ':REQUIRED-INSTANCE-VARIABLES))
                   1402:        (OR (MEMQ REQV (FLAVOR-ALL-INSTANCE-VARIABLES FL))
                   1403:            (MEMQ REQV MISSING-INSTANCE-VARIABLES)
                   1404:            (PROGN (PUSH REQV MISSING-INSTANCE-VARIABLES)
                   1405:                   (PUSH (CONS (FIRST FFLS) REQV) REQUIRING-FLAVOR-ALIST))))
                   1406:       (DOLIST (REQF (GET PL ':REQUIRED-FLAVORS))
                   1407:        (OR (MEMQ REQF (FLAVOR-DEPENDS-ON-ALL FL))
                   1408:            (MEMQ REQF MISSING-FLAVORS)
                   1409:            (PROGN (PUSH REQF MISSING-FLAVORS)
                   1410:                   (PUSH (CONS (FIRST FFLS) REQF) REQUIRING-FLAVOR-ALIST)))))))
                   1411: 
                   1412: ;This is the default handler for flavors.
                   1413: (DEFUN FLAVOR-UNCLAIMED-MESSAGE (MESSAGE ARGS)
                   1414:   (DECLARE (SPECIAL SELF))
                   1415:   (FORMAT T "The object ")
                   1416:   (PRINT SELF)
                   1417:   (FERROR ':UNCLAIMED-MESSAGE " received a ~S message, which went unclaimed.
                   1418: The rest of the message was ~S~%" MESSAGE ARGS))
                   1419: 
                   1420: ;Return an alist of operations and their handlers.
                   1421: (DEFUN FLAVOR-METHOD-ALIST (FL)
                   1422:   (IF (SYMBOLP FL) (SETQ FL (GET FL 'FLAVOR)))
                   1423:   (IF FL
                   1424:       (LET ((HT (FLAVOR-METHOD-HASH-TABLE FL))
                   1425:            (ALIST NIL))
                   1426:        (AND HT
                   1427:             (MAPHASH #'(LAMBDA (OP METH-LOCATIVE &REST IGNORE)
                   1428:                           (DECLARE (SPECIAL ALIST))
                   1429:                           (PUSH (CONS OP (CAR METH-LOCATIVE)) ALIST))
                   1430:                      HT))
                   1431:            ALIST)))
                   1432: 
                   1433: ;; Make the instance-variable getting and setting methods
                   1434: ;; Updated 7Jul84 SMH@MIT-EMS:  As an apparent efficiency hack, the original
                   1435: ;; Lisp Machine code pushed each defmethod only if **just-compiling** were set
                   1436: ;; or the method were not yet defined.  The **just-compiling** switch has
                   1437: ;; unfortunately disappeared from the Franz version.  This caused
                   1438: ;; REcompilations of a flavor by a single instance of Liszt to omit all
                   1439: ;; automatic methods.  The bypass of the defmethod if the method is already
                   1440: ;; defined has thus been deleted.
                   1441: (DEFUN COMPOSE-AUTOMATIC-METHODS (FL &AUX VV FORMS)
                   1442:        (DOLIST (V (FLAVOR-GETTABLE-INSTANCE-VARIABLES FL))
                   1443:               (SETQ VV (CORRESPONDING-KEYWORD V))
                   1444:               (LET ((METH `(:METHOD ,(FLAVOR-NAME FL) ,VV)))
                   1445:                    (PUSH `(DEFMETHOD (,(FLAVOR-NAME FL) ,VV) () ,V)
                   1446:                          FORMS)))
                   1447:        (DOLIST (V (FLAVOR-SETTABLE-INSTANCE-VARIABLES FL))
                   1448:               (SETQ VV (INTERN (FORMAT () ":set-~A" V)))
                   1449:               (LET ((METH `(:METHOD ,(FLAVOR-NAME FL) ,VV)))
                   1450:                    (PUSH `(DEFMETHOD (,(FLAVOR-NAME FL) ,VV) (VALUE)
                   1451:                                      (SETQ ,V VALUE))
                   1452:                          FORMS)))
                   1453:        (NREVERSE FORMS))
                   1454: 
                   1455: ;Given a symbol return the corresponding one in the keyword package
                   1456: (DEFUN CORRESPONDING-KEYWORD (SYMBOL)
                   1457:   (IF (= #/: (GETCHARN SYMBOL 1)) SYMBOL
                   1458:       (INTERN (CONCAT ":" SYMBOL))))
                   1459: 
                   1460: ;Figure out the information needed to instantiate a flavor quickly.
                   1461: 
                   1462: ;We store these three properties on the flavor:
                   1463: ;INSTANCE-VARIABLE-INITIALIZATIONS - alist of (ivar-index . init-form)
                   1464: ;REMAINING-DEFAULT-PLIST - a default plist from which kwds that init ivars 
                   1465: ;                         have been removed.
                   1466: ;ALL-INITABLE-INSTANCE-VARIABLES - 
                   1467: ;      a list parallel to FLAVOR-ALL-INSTANCE-VARIABLES which has either
                   1468: ;      the keyword to init with or NIL.
                   1469: ;REMAINING-INIT-KEYWORDS - 
                   1470: ;      the init keywords that are handled and don't just init ivars.
                   1471: 
                   1472: ;We also set up the FLAVOR-DEFAULT-HANDLER of the flavor.
                   1473: 
                   1474: (DEFUN COMPOSE-FLAVOR-INITIALIZATIONS (FL &AUX ALIST
                   1475:                                       (REMAINING-DEFAULT-PLIST (LIST NIL))
                   1476:                                       ALL-INITABLE-IVARS)
                   1477:   (SETQ ALL-INITABLE-IVARS (MAKE-LIST
                   1478:                            (LENGTH (FLAVOR-ALL-INSTANCE-VARIABLES FL))))
                   1479:   ;; First make the mask saying which ivars can be inited by init keywords.
                   1480:   (DOLIST (FFL (FLAVOR-DEPENDS-ON-ALL FL))
                   1481:     (LET ((FFL (GET-FLAVOR FFL)))
                   1482:       (OR (FLAVOR-DEFAULT-HANDLER FL)
                   1483:          (SETF (FLAVOR-DEFAULT-HANDLER FL)
                   1484:                (GET (FLAVOR-PLIST FFL) ':DEFAULT-HANDLER)))
                   1485:       (DOLIST (IIV (FLAVOR-INITABLE-INSTANCE-VARIABLES FFL))
                   1486:        (LET ((INDEX (FIND-POSITION-IN-LIST (CDR IIV)
                   1487:                        (FLAVOR-ALL-INSTANCE-VARIABLES FL))))
                   1488:          (AND INDEX
                   1489:               (SETF (NTH INDEX ALL-INITABLE-IVARS)
                   1490:                     (CAR IIV)))))))
                   1491:   ;; Then look at all the default init plists, for anything there that
                   1492:   ;; initializes an instance variable.  If it does, make an entry on ALIST.
                   1493:   ;; Any that doesn't initialize a variable, put on the "remaining" list.
                   1494:   (DOLIST (FFL (FLAVOR-DEPENDS-ON-ALL FL))
                   1495:     (SETQ FFL (GET-FLAVOR FFL))
                   1496:     (DO ((L (GET (FLAVOR-PLIST FFL) ':DEFAULT-INIT-PLIST) (CDDR L))) ((NULL L))
                   1497:       (LET* ((KEYWORD (CAR L)) (ARG (CADR L))
                   1498:             (INDEX (FIND-POSITION-IN-LIST KEYWORD ALL-INITABLE-IVARS)))
                   1499:        (IF INDEX
                   1500:            (OR (ASSQ INDEX ALIST)
                   1501:                (PUSH (LIST INDEX ARG)
                   1502:                      ALIST))
                   1503:          ;; This keyword does not just initialize an instance variable.
                   1504:            (OR (MEMQ-ALTERNATED KEYWORD (CDR REMAINING-DEFAULT-PLIST))
                   1505:                (PUTPROP REMAINING-DEFAULT-PLIST ARG KEYWORD))))))
                   1506:   ;; Then, look for default values provided in list of instance vars.
                   1507:   (DOLIST (FFL (FLAVOR-DEPENDS-ON-ALL FL))
                   1508:     (SETQ FFL (GET-FLAVOR FFL))
                   1509:     (DOLIST (V (FLAVOR-LOCAL-INSTANCE-VARIABLES FFL))
                   1510:       (AND (NOT (ATOM V))
                   1511:           ;; When we find one, put it in if there is no init for that variable yet.
                   1512:           (LET ((INDEX (FIND-POSITION-IN-LIST (CAR V)
                   1513:                               (FLAVOR-ALL-INSTANCE-VARIABLES FL))))
                   1514:             (AND (NOT (ASSQ INDEX ALIST))
                   1515:                  (PUSH (LIST INDEX
                   1516:                              (CADR V))
                   1517:                        ALIST)))))) 
                   1518:   (SETF (FLAVOR-INSTANCE-VARIABLE-INITIALIZATIONS FL)
                   1519:        (SORTCAR ALIST #'LESSP))
                   1520:   (SETF (FLAVOR-REMAINING-DEFAULT-PLIST FL) (CDR REMAINING-DEFAULT-PLIST))
                   1521:   (SETF (FLAVOR-ALL-INITABLE-INSTANCE-VARIABLES FL) ALL-INITABLE-IVARS)
                   1522:   (SETF (FLAVOR-REMAINING-INIT-KEYWORDS FL)
                   1523:        (LOOP FOR K IN (FLAVOR-ALLOWED-INIT-KEYWORDS FL)
                   1524:              UNLESS (MEMQ K ALL-INITABLE-IVARS)
                   1525:              COLLECT K)))
                   1526: 
                   1527: ; Method-combination functions.  Found on the SI:METHOD-COMBINATION property
                   1528: ; of the combination-type.  These are passed the flavor structure, and the
                   1529: ; magic-list entry, and must return the function-spec for the handler
                   1530: ; to go into the select-method, defining any necessary functions.
                   1531: ; This function interprets combination-type-arg,
                   1532: ; which for many combination-types is either :BASE-FLAVOR-FIRST or :BASE-FLAVOR-LAST.
                   1533: 
                   1534: ; :DAEMON combination
                   1535: ; The primary method is the outermost untyped-method (or :DEFAULT).
                   1536: ; The :BEFORE methods are called base-flavor-last, the :AFTER methods are called
                   1537: ; base-flavor-first.  An important optimization is not to generate a combined-method
                   1538: ; if there is only a primary method.  You are allowed to omit the primary method
                   1539: ; if there are any daemons (I'm not convinced this is really a good idea) in which
                   1540: ; case the method's returned value will be NIL.
                   1541: (DEFUN (:DAEMON METHOD-COMBINATION) (FL MAGIC-LIST-ENTRY)
                   1542:   (LET ((PRIMARY-METHOD (CAR (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY NIL '(:BEFORE :AFTER) T
                   1543:                                                  ':BASE-FLAVOR-LAST)))
                   1544:        (BEFORE-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY ':BEFORE T T
                   1545:                                             ':BASE-FLAVOR-LAST))
                   1546:        (AFTER-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY ':AFTER T T
                   1547:                                            ':BASE-FLAVOR-FIRST))
                   1548:        (WRAPPERS-P (SPECIALLY-COMBINED-METHODS-PRESENT MAGIC-LIST-ENTRY)))
                   1549:     ;; Remove shadowed primary methods from the magic-list-entry so that it won't look like
                   1550:     ;; we depend on them (which could cause extraneous combined-method recompilation).
                   1551:     (LET ((MLE (ASSQ NIL (CDDDR MAGIC-LIST-ENTRY))))
                   1552:       (AND (CDDR MLE)
                   1553:           (SETF (CDR MLE) (LIST PRIMARY-METHOD))))
                   1554:     (OR (AND (NOT WRAPPERS-P) (NULL BEFORE-METHODS) (NULL AFTER-METHODS) PRIMARY-METHOD)
                   1555:        (HAVE-COMBINED-METHOD FL MAGIC-LIST-ENTRY)
                   1556:        (MAKE-COMBINED-METHOD FL MAGIC-LIST-ENTRY
                   1557:           (DAEMON-COMBINATION PRIMARY-METHOD BEFORE-METHODS AFTER-METHODS)))))
                   1558: 
                   1559: (DEFUN DAEMON-COMBINATION (PRIMARY-METHOD BEFORE-METHODS AFTER-METHODS
                   1560:                           &OPTIONAL OR-METHODS AND-METHODS)
                   1561:   (LET ((INNER-CALL (AND PRIMARY-METHOD (METHOD-CALL PRIMARY-METHOD))))
                   1562:     (IF (AND INNER-CALL AFTER-METHODS)
                   1563:        (SETQ INNER-CALL `(MULTIPLE-VALUE (.VAL1. .VAL2. .VAL3.)
                   1564:                            ,INNER-CALL)))
                   1565:     (AND OR-METHODS (SETQ INNER-CALL
                   1566:                          `(OR ,@(MAPCAR 'METHOD-CALL OR-METHODS)
                   1567:                               ,INNER-CALL)))
                   1568:     (AND AND-METHODS (SETQ INNER-CALL
                   1569:                           `(AND ,@(MAPCAR 'METHOD-CALL AND-METHODS)
                   1570:                                 ,INNER-CALL)))
                   1571:     `(PROGN 
                   1572:        ,@(MAPCAR 'METHOD-CALL BEFORE-METHODS)
                   1573:        ,(IF AFTER-METHODS
                   1574:            ;; Kludge to return a few multiple values
                   1575:            `(PROG (.VAL1. .VAL2. .VAL3.)
                   1576:                   ,INNER-CALL
                   1577:                   ,@(MAPCAR 'METHOD-CALL AFTER-METHODS)
                   1578:                   (RETURN .VAL1. .VAL2. .VAL3.))
                   1579:            ;; No :AFTER methods, hair not required
                   1580:            ;; You are allowed to not have a primary method
                   1581:            INNER-CALL))))
                   1582: 
                   1583: (DEFUN METHOD-CALL (METHOD)
                   1584:   `(LEXPR-FUNCALL #',(METHOD-FUNCTION-NAME METHOD) .DAEMON-CALLER-ARGS.))
                   1585: 
                   1586: ; :DAEMON-WITH-OVERRIDE combination
                   1587: ; This is the same as :DAEMON (the default), except that :OVERRIDE type methods
                   1588: ; are combined with the :BEFORE-primary-:AFTER methods in an OR.  This allows
                   1589: ; overriding of the main methods function.  For example, a combined method as follows
                   1590: ; might be generated: (OR (FOO-OVERRIDE-BAR-METHOD) (PROGN (FOO-BEFORE-BAR-METHOD)))
                   1591: (DEFUN (:DAEMON-WITH-OVERRIDE METHOD-COMBINATION) (FL MAGIC-LIST-ENTRY)
                   1592:   (LET ((PRIMARY-METHOD (CAR (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY NIL
                   1593:                                                  '(:BEFORE :AFTER :OVERRIDE) T
                   1594:                                                  ':BASE-FLAVOR-LAST)))
                   1595:        (BEFORE-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY ':BEFORE T T
                   1596:                                             ':BASE-FLAVOR-LAST))
                   1597:        (AFTER-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY ':AFTER T T
                   1598:                                            ':BASE-FLAVOR-FIRST))
                   1599:        (WRAPPERS-P (SPECIALLY-COMBINED-METHODS-PRESENT MAGIC-LIST-ENTRY))
                   1600:        (OVERRIDE-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY
                   1601:                                               ':OVERRIDE T T NIL)))
                   1602:     ;; Remove shadowed primary methods from the magic-list-entry so that it won't look like
                   1603:     ;; we depend on them (which could cause extraneous combined-method recompilation).
                   1604:     (LET ((MLE (ASSQ NIL (CDDDR MAGIC-LIST-ENTRY))))
                   1605:       (AND (CDDR MLE)
                   1606:           (SETF (CDR MLE) (LIST PRIMARY-METHOD))))
                   1607:     (OR (AND (NOT WRAPPERS-P) (NULL BEFORE-METHODS) (NULL AFTER-METHODS)
                   1608:             (NULL OVERRIDE-METHODS)
                   1609:             PRIMARY-METHOD)
                   1610:        (HAVE-COMBINED-METHOD FL MAGIC-LIST-ENTRY)
                   1611:        (MAKE-COMBINED-METHOD FL MAGIC-LIST-ENTRY
                   1612:          `(OR ,@(MAPCAR 'METHOD-CALL OVERRIDE-METHODS)
                   1613:               ,(DAEMON-COMBINATION PRIMARY-METHOD BEFORE-METHODS AFTER-METHODS))))))
                   1614: 
                   1615: ; :DAEMON-WITH-OR combination
                   1616: ; This is the same as :DAEMON (the default), except that :OR type methods
                   1617: ; are combined with the primary methods inside an OR, and used in place of
                   1618: ; the primary method in :DAEMON type combination.
                   1619: ; For example, the following combined method might be generated:
                   1620: ; (PROGN (FOO-BEFORE-BAR-METHOD)
                   1621: ;       (PROG (.VAL1. .VAL2. .VAL3.)
                   1622: ;             (OR (FOO-OR-BAR-METHOD)
                   1623: ;                 (BAZ-OR-BAR-METHOD)
                   1624: ;                 (MULTIPLE-VALUE (.VAL1. .VAL2. .VAL3.)
                   1625: ;                   (BUZZ-PRIMARY-METHOD)))
                   1626: ;             (FOO-AFTER-BAR-METHOD)
                   1627: ;             (RETURN .VAL1. .VAL2. .VAL3.)))
                   1628: 
                   1629: (DEFUN (:DAEMON-WITH-OR METHOD-COMBINATION) (FL MAGIC-LIST-ENTRY)
                   1630:   (LET ((PRIMARY-METHOD (CAR (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY NIL '(:BEFORE :AFTER :OR) T
                   1631:                                                  ':BASE-FLAVOR-LAST)))
                   1632:        (BEFORE-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY ':BEFORE T T
                   1633:                                             ':BASE-FLAVOR-LAST))
                   1634:        (AFTER-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY ':AFTER T T
                   1635:                                            ':BASE-FLAVOR-FIRST))
                   1636:        (WRAPPERS-P (SPECIALLY-COMBINED-METHODS-PRESENT MAGIC-LIST-ENTRY))
                   1637:        (OR-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY ':OR T T NIL)))
                   1638:     ;; Remove shadowed primary methods from the magic-list-entry so that it won't look like
                   1639:     ;; we depend on them (which could cause extraneous combined-method recompilation).
                   1640:     (LET ((MLE (ASSQ NIL (CDDDR MAGIC-LIST-ENTRY))))
                   1641:       (AND (CDDR MLE)
                   1642:           (SETF (CDR MLE) (LIST PRIMARY-METHOD))))
                   1643:     (OR (AND (NOT WRAPPERS-P) (NULL BEFORE-METHODS) (NULL AFTER-METHODS)
                   1644:             (NULL OR-METHODS)
                   1645:             PRIMARY-METHOD)
                   1646:        (HAVE-COMBINED-METHOD FL MAGIC-LIST-ENTRY)
                   1647:        (MAKE-COMBINED-METHOD FL MAGIC-LIST-ENTRY
                   1648:          (DAEMON-COMBINATION PRIMARY-METHOD BEFORE-METHODS AFTER-METHODS
                   1649:                              OR-METHODS)))))
                   1650: 
                   1651: ; :DAEMON-WITH-AND combination
                   1652: ; This is the same as :DAEMON (the default), except that :AND type methods
                   1653: ; are combined with the primary methods inside an AND, and used in place of
                   1654: ; the primary method in :DAEMON type combination.
                   1655: ; For example, the following combined method might be generated:
                   1656: ; (PROGN (FOO-BEFORE-BAR-METHOD)
                   1657: ;       (PROG (.VAL1. .VAL2. .VAL3.)
                   1658: ;             (AND (FOO-AND-BAR-METHOD)
                   1659: ;                  (BAZ-AND-BAR-METHOD)
                   1660: ;                  (MULTIPLE-VALUE (.VAL1. .VAL2. .VAL3.)
                   1661: ;                    (BUZZ-PRIMARY-METHOD)))
                   1662: ;             (FOO-AFTER-BAR-METHOD)
                   1663: ;             (RETURN .VAL1. .VAL2. .VAL3.)))
                   1664: 
                   1665: (DEFUN (:DAEMON-WITH-AND METHOD-COMBINATION) (FL MAGIC-LIST-ENTRY)
                   1666:   (LET ((PRIMARY-METHOD (CAR (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY NIL '(:BEFORE :AFTER :AND)
                   1667:                                                  T ':BASE-FLAVOR-LAST)))
                   1668:        (BEFORE-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY ':BEFORE T T
                   1669:                                             ':BASE-FLAVOR-LAST))
                   1670:        (AFTER-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY ':AFTER T T
                   1671:                                            ':BASE-FLAVOR-FIRST))
                   1672:        (WRAPPERS-P (SPECIALLY-COMBINED-METHODS-PRESENT MAGIC-LIST-ENTRY))
                   1673:        (AND-METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY ':AND T T NIL)))
                   1674:     ;; Remove shadowed primary methods from the magic-list-entry so that it won't look like
                   1675:     ;; we depend on them (which could cause extraneous combined-method recompilation).
                   1676:     (LET ((MLE (ASSQ NIL (CDDDR MAGIC-LIST-ENTRY))))
                   1677:       (AND (CDDR MLE)
                   1678:           (SETF (CDR MLE) (LIST PRIMARY-METHOD))))
                   1679:     (OR (AND (NOT WRAPPERS-P) (NULL BEFORE-METHODS) (NULL AFTER-METHODS)
                   1680:             (NULL AND-METHODS)
                   1681:             PRIMARY-METHOD)
                   1682:        (HAVE-COMBINED-METHOD FL MAGIC-LIST-ENTRY)
                   1683:        (MAKE-COMBINED-METHOD FL MAGIC-LIST-ENTRY
                   1684:          (DAEMON-COMBINATION PRIMARY-METHOD BEFORE-METHODS AFTER-METHODS
                   1685:                              NIL AND-METHODS)))))
                   1686: 
                   1687: ; :LIST combination
                   1688: ; No typed-methods allowed.  Returns a list of the results of all the methods.
                   1689: ; There will always be a combined-method, even if only one method to be called.
                   1690: (DEFUN (:LIST METHOD-COMBINATION) (FL MAGIC-LIST-ENTRY)
                   1691:   (OR (HAVE-COMBINED-METHOD FL MAGIC-LIST-ENTRY)
                   1692:       (MAKE-COMBINED-METHOD FL MAGIC-LIST-ENTRY
                   1693:            (CONS 'LIST (MAPCAR 'METHOD-CALL
                   1694:                                (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY NIL NIL NIL NIL))))))
                   1695: 
                   1696: ; :INVERSE-LIST combination
                   1697: ; No typed-methods allowed.  Apply each method to an element of the list.  Given
                   1698: ; the result of a :LIST-combined method with the same ordering, and corresponding
                   1699: ; method definitions, the result that emerged from each component flavor gets handed
                   1700: ; back to that same flavor.  The combined-method returns no particular value.
                   1701: (DEFUN (:INVERSE-LIST METHOD-COMBINATION) (FL MAGIC-LIST-ENTRY)
                   1702:   (OR (HAVE-COMBINED-METHOD FL MAGIC-LIST-ENTRY)
                   1703:       (MAKE-COMBINED-METHOD FL MAGIC-LIST-ENTRY
                   1704:         `(LET ((.FOO. (CADR .DAEMON-CALLER-ARGS.)))
                   1705:            . ,(DO ((ML (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY NIL NIL NIL NIL) (CDR ML))
                   1706:                    (R NIL))
                   1707:                   ((NULL ML) (NREVERSE R))
                   1708:                 (PUSH `(FUNCALL #',(CAR ML)
                   1709:                          (CAR .DAEMON-CALLER-ARGS.) (CAR .FOO.))
                   1710:                       R)
                   1711:                 (AND (CDR ML) (PUSH '(SETQ .FOO. (CDR .FOO.)) R)))))))
                   1712: 
                   1713: ; Combination types PROGN, AND, OR, MAX, MIN, +, APPEND, NCONC
                   1714: ; These just call all the untyped methods, inside the indicated special form.
                   1715: ; As an optimization, if there is only one method it is simply called.
                   1716: ; ?? There should be hair where methods with an extra keyword in them
                   1717: ; get to act as conditionals controlling which other methods get called,
                   1718: ; if anyone can ever specify exactly what this means.
                   1719: (DEFPROP :PROGN SIMPLE-METHOD-COMBINATION METHOD-COMBINATION)
                   1720: (DEFPROP :AND SIMPLE-METHOD-COMBINATION METHOD-COMBINATION)
                   1721: (DEFPROP :OR SIMPLE-METHOD-COMBINATION METHOD-COMBINATION)
                   1722: (DEFPROP :MAX SIMPLE-METHOD-COMBINATION METHOD-COMBINATION)
                   1723: (DEFPROP :MIN SIMPLE-METHOD-COMBINATION METHOD-COMBINATION)
                   1724: (DEFPROP :+ SIMPLE-METHOD-COMBINATION METHOD-COMBINATION)
                   1725: (DEFPROP :APPEND SIMPLE-METHOD-COMBINATION METHOD-COMBINATION)
                   1726: (DEFPROP :NCONC SIMPLE-METHOD-COMBINATION METHOD-COMBINATION)
                   1727: 
                   1728: ; The following "tasteless" crock is necessary to make all work in Franz:
                   1729: (eval-when (load eval) (loop for (to . from) in
                   1730:                             '((:progn . progn)
                   1731:                               (:and . and)
                   1732:                               (:or . or)
                   1733:                               (:max . max)
                   1734:                               (:min . min)
                   1735:                               (:+ . +)
                   1736:                               (:append . append)
                   1737:                               (:nconc . nconc))
                   1738:                              do
                   1739:                              (putd to (getd from))))
                   1740: 
                   1741: (DEFUN SIMPLE-METHOD-COMBINATION (FL MAGIC-LIST-ENTRY)
                   1742:   (LET ((METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY NIL NIL NIL NIL))
                   1743:        (WRAPPERS-P (SPECIALLY-COMBINED-METHODS-PRESENT MAGIC-LIST-ENTRY)))
                   1744:     (OR (AND (NOT WRAPPERS-P) (NULL (CDR METHODS)) (CAR METHODS))
                   1745:        (HAVE-COMBINED-METHOD FL MAGIC-LIST-ENTRY)
                   1746:        (MAKE-COMBINED-METHOD FL MAGIC-LIST-ENTRY
                   1747:           (CONS (CADR MAGIC-LIST-ENTRY)
                   1748:                 (MAPCAR 'METHOD-CALL
                   1749:                         METHODS))))))
                   1750: 
                   1751: ; :PASS-ON combination
                   1752: ; The values from the individual methods are the arguments to the next one;
                   1753: ; the values from the last method are the values returned by the combined
                   1754: ; method.  Format is 
                   1755: ;    (:METHOD-COMBINATION (:PASS-ON (ORDERING . ARGLIST)) . OPERATION-NAMES)
                   1756: ; ORDERING is :BASE-FLAVOR-FIRST or :BASE-FLAVOR-LAST.  ARGLIST can have 
                   1757: ; &AUX and &OPTIONAL.
                   1758: 
                   1759: (DEFUN (:PASS-ON METHOD-COMBINATION) (FL MAGIC-LIST-ENTRY)
                   1760:   (LET ((METHODS (GET-CERTAIN-METHODS MAGIC-LIST-ENTRY NIL NIL NIL
                   1761:                                      (CAADDR MAGIC-LIST-ENTRY)))
                   1762:        (ARGLIST (CDADDR MAGIC-LIST-ENTRY))
                   1763:        ARGS REST-ARG-P)
                   1764:     (DO ((L ARGLIST (CDR L))
                   1765:         (ARG)
                   1766:         (NL NIL))
                   1767:        ((NULL L)
                   1768:         (SETQ ARGS (NREVERSE NL)))
                   1769:       (SETQ ARG (CAR L))
                   1770:       (AND (LISTP ARG)
                   1771:           (SETQ ARG (CAR ARG)))
                   1772:       (COND ((EQ ARG '&REST)
                   1773:             (SETQ REST-ARG-P T))
                   1774:            ((EQ ARG '&AUX))
                   1775:            (T
                   1776:             (PUSH ARG NL))))      
                   1777:     (OR (HAVE-COMBINED-METHOD FL MAGIC-LIST-ENTRY)
                   1778:        (MAKE-COMBINED-METHOD FL MAGIC-LIST-ENTRY
                   1779:          `(DESTRUCTURING-BIND ,(CONS '.OPERATION. ARGLIST) SI:.DAEMON-CALLER-ARGS.
                   1780:             . ,(DO ((METHS METHODS (CDR METHS))
                   1781:                     (LIST NIL)
                   1782:                     (METH))
                   1783:                    ((NULL METHS)
                   1784:                     (NREVERSE LIST))
                   1785:                  (SETQ METH `(,(IF REST-ARG-P
                   1786:                                    'LEXPR-FUNCALL
                   1787:                                  'FUNCALL)
                   1788:                               #',(CAR METHS) .OPERATION. . ,ARGS))
                   1789:                  (AND (CDR METHS)
                   1790:                       (SETQ METH (IF (NULL (CDR ARGS))
                   1791:                                      `(SETQ ,(CAR ARGS) ,METH)
                   1792:                                    `(MULTIPLE-VALUE ,ARGS ,METH))))
                   1793:                  (PUSH METH LIST)))))))
                   1794: 
                   1795: ; This function does most of the analysis of the magic-list-entry needed by
                   1796: ; method-combination functions, including most error checking.
                   1797: ; Returns a list of the method symbols for METHOD-TYPE extracted from 
                   1798: ; MAGIC-LIST-ENTRY.  This value is shared with the data structure, don't 
                   1799: ; bash it.  OTHER-METHODS-ALLOWED is a list of method types not to complain
                   1800: ;about (T = allow all).
                   1801: ;   NO-METHODS-OK = NIL means to complain if the returned value would be NIL.
                   1802: ;   ORDERING-DECLARATION is :BASE-FLAVOR-FIRST, :BASE-FLAVOR-LAST, or NIL 
                   1803: ;    meaning take one of those symbols from the MAGIC-LIST-ENTRY."
                   1804: 
                   1805: (DEFUN GET-CERTAIN-METHODS (MAGIC-LIST-ENTRY METHOD-TYPE OTHER-METHODS-ALLOWED
                   1806:                            NO-METHODS-OK ORDERING-DECLARATION
                   1807:                            &AUX (METHODS NIL))
                   1808:   ;; Find the methods of the desired type, and barf at any extraneous methods
                   1809:   (DOLIST (X (CDDDR MAGIC-LIST-ENTRY))
                   1810:     (COND ((EQ (CAR X) METHOD-TYPE) (SETQ METHODS (CDR X)))
                   1811:          ((ASSQ (CAR X) *SPECIALLY-COMBINED-METHOD-TYPES*) ) ;Wrappers ignored at this level
                   1812:          ((OR (EQ OTHER-METHODS-ALLOWED T) (MEMQ (CAR X) OTHER-METHODS-ALLOWED)) )
                   1813:          (T (FERROR () "~S ~S method(s) illegal when using :~A method-combination"
                   1814:                         (CAR X) (CAR MAGIC-LIST-ENTRY)
                   1815:                         (OR (CADR MAGIC-LIST-ENTRY) ':DAEMON)))))
                   1816:   ;; Complain if no methods supplied
                   1817:   (AND (NULL METHODS) (NOT NO-METHODS-OK)
                   1818:        (FERROR () "No ~S ~S method(s) supplied to :~A method-combination"
                   1819:                   METHOD-TYPE (CAR MAGIC-LIST-ENTRY) (CADR MAGIC-LIST-ENTRY)))
                   1820:   ;; Get methods into proper order.  Don't use NREVERSE!
                   1821:   (SELECTQ (OR ORDERING-DECLARATION (SETQ ORDERING-DECLARATION (CADDR MAGIC-LIST-ENTRY)))
                   1822:     (:BASE-FLAVOR-FIRST )
                   1823:     (:BASE-FLAVOR-LAST (SETQ METHODS (REVERSE METHODS)))
                   1824:     (OTHERWISE (FERROR () "~S invalid method combination order;
                   1825:  must be :BASE-FLAVOR-FIRST or :BASE-FLAVOR-LAST"
                   1826:                           ORDERING-DECLARATION)))
                   1827:   METHODS)
                   1828: 
                   1829: (DEFUN SPECIALLY-COMBINED-METHODS-PRESENT (MLE)
                   1830:   (LOOP FOR (TYPE) IN (CDDDR MLE)
                   1831:        THEREIS (ASSQ TYPE *SPECIALLY-COMBINED-METHOD-TYPES*)))
                   1832: 
                   1833: ;; It is up to the caller to decide that a combined-method is called for at all.
                   1834: ;; If one is, this function decides whether it already exists OK or needs
                   1835: ;; to be recompiled.  Returns the symbol for the combined method if it is
                   1836: ;; still valid, otherwise returns NIL.
                   1837: ;; Always canonicalizes the magic-list-entry, since it will be needed
                   1838: ;; canonicalized later.
                   1839: (DEFUN HAVE-COMBINED-METHOD (FL MAGIC-LIST-ENTRY
                   1840:                             &AUX OPERATION-NAME CMS MTE OLD-MLE OLD-CMS TEM OMETH)
                   1841:   ;; Canonicalize the magic-list-entry so can compare with EQUAL
                   1842:   (SETF (CDDDR MAGIC-LIST-ENTRY)               ;Canonicalize before comparing
                   1843:        (SORTCAR (CDDDR MAGIC-LIST-ENTRY) #'ALPHALESSP))        ;Sort by method-type
                   1844:   (SETQ OPERATION-NAME (CAR MAGIC-LIST-ENTRY))
                   1845:   ;; See if we can inherit one in either the current or future (being-compiled) world,
                   1846:   ;; or use an existing combined method of this flavor.
                   1847:   ;; Get the :COMBINED method function spec for this flavor.  Note that if a suitable
                   1848:   ;; one can be inherited, we will do so.
                   1849:   ;; *USE-OLD-COMBINED-METHODS* controls whether we reuse an existing one for this
                   1850:   ;; flavor; if we inherit one it will always be up-to-date already.
                   1851:   ;; If all OK, return the function spec, else return NIL if new combined method must be made.
                   1852:   (OR (DOLIST (FFL (FLAVOR-DEPENDS-ON-ALL FL))
                   1853:        (LET ((FLAVOR1 (GET-FLAVOR FFL)))
                   1854:          (AND (OR (NEQ FLAVOR1 FL) *USE-OLD-COMBINED-METHODS*)
                   1855:               ;; ^ Combined methods of this flavor can be used only if permitted.
                   1856:               (SETQ MTE (ASSQ OPERATION-NAME (FLAVOR-METHOD-TABLE FLAVOR1)))
                   1857:               (SETQ OMETH (METH-LOOKUP ':COMBINED (CDDDR MTE)))
                   1858:               (METH-DEFINEDP OMETH)
                   1859:               (METH-DEFINITION OMETH)
                   1860:               (SETQ CMS (METH-FUNCTION-SPEC OMETH))
                   1861:               (EQUAL MAGIC-LIST-ENTRY
                   1862:                      (SETQ TEM (GET (METH-PLIST OMETH) 'COMBINED-METHOD-DERIVATION)))
                   1863:               (RETURN CMS)))
                   1864:        ;Save first combined-method seen for tracing, it's the one we would
                   1865:        ;have been most likely to inherit
                   1866:        (OR OLD-CMS (NULL CMS) (NULL TEM)
                   1867:            (SETQ OLD-CMS CMS OLD-MLE TEM)))
                   1868: 
                   1869:       ;; Have to make a new combined method.  Trace if desired, but return NIL in any case.
                   1870:       (PROGN
                   1871:        (COND (*FLAVOR-COMPILE-TRACE*
                   1872:               (FORMAT *FLAVOR-COMPILE-TRACE*
                   1873:                       "~&~S's ~S combined method needs to be recompiled~%to come from "
                   1874:                       (FLAVOR-NAME FL) OPERATION-NAME)
                   1875:               (PRINT-COMBINED-METHOD-DERIVATION MAGIC-LIST-ENTRY *FLAVOR-COMPILE-TRACE*)
                   1876:               (COND (OLD-CMS
                   1877:                      (FORMAT *FLAVOR-COMPILE-TRACE*
                   1878:                              "~%rather than using ~S which comes from " OLD-CMS)
                   1879:                      (PRINT-COMBINED-METHOD-DERIVATION OLD-MLE *FLAVOR-COMPILE-TRACE*))
                   1880:                     ((NOT *USE-OLD-COMBINED-METHODS*)
                   1881:                      (FORMAT *FLAVOR-COMPILE-TRACE* "~%because of forced recompilation.")))))
                   1882:        NIL)))
                   1883: 
                   1884: 
                   1885: (DEFUN PRINT-COMBINED-METHOD-DERIVATION (MLE STREAM)
                   1886:   (LOOP FOR (TYPE . FUNCTION-SPECS) IN (CDDDR MLE)
                   1887:        DO (LOOP FOR FUNCTION-SPEC IN FUNCTION-SPECS DO (FORMAT STREAM "~S " FUNCTION-SPEC)))
                   1888:   (IF (OR (CADR MLE) (CADDR MLE))
                   1889:       (FORMAT STREAM "with method-combination ~S ~S" (CADR MLE) (CADDR MLE))))
                   1890: 
                   1891: ;; This function creates a combined-method, and returns the appropriate function spec.
                   1892: ;; Its main job in life is to take care of wrappers.  Note the combined method
                   1893: ;; always takes a single &REST argument named .DAEMON-CALLER-ARGS.
                   1894: ;; FORM is a single form to be used as the body.
                   1895: (DEFUN MAKE-COMBINED-METHOD (FL MAGIC-LIST-ENTRY FORM &AUX FSPEC WRAPPERS)
                   1896:   ;; Get the function spec which will name the combined-method
                   1897:   (SETQ FSPEC `(:METHOD ,(FLAVOR-NAME FL) :COMBINED ,(CAR MAGIC-LIST-ENTRY)))
                   1898:   ;; Put the wrappers around the form.  The base-flavor wrapper goes on the inside.
                   1899:   (SETQ WRAPPERS (GET-SPECIALLY-COMBINED-METHODS MAGIC-LIST-ENTRY FL))
                   1900:   (DOLIST (METHOD WRAPPERS)
                   1901:     (SETQ FORM (FUNCALL (CADR (ASSQ (CADDR METHOD) *SPECIALLY-COMBINED-METHOD-TYPES*))
                   1902:                        METHOD FORM)))
                   1903:   ;; Remember that it's going to be there, for HAVE-COMBINED-METHOD
                   1904:   (FLAVOR-NOTICE-METHOD FSPEC)
                   1905:   ;; Compile the function.  It will be inserted into the flavor's tables either
                   1906:   ;; now or when the QFASL file is loaded.
                   1907:   (COMPILE-AT-APPROPRIATE-TIME
                   1908:     FL
                   1909:     FSPEC
                   1910:     `(LAMBDA (&REST .DAEMON-CALLER-ARGS.)
                   1911:        .DAEMON-CALLER-ARGS.
                   1912:        ,FORM)
                   1913:     `(FUNCTION-SPEC-PUTPROP ',FSPEC
                   1914:                            ',MAGIC-LIST-ENTRY
                   1915:                            'COMBINED-METHOD-DERIVATION))
                   1916:   FSPEC)
                   1917: 
                   1918: 
                   1919: (LOCAL-DECLARE ((SPECIAL *FL*))
                   1920: (DEFUN GET-SPECIALLY-COMBINED-METHODS (MLE *FL*)
                   1921:   (SORT (LOOP FOR (TYPE . FSPECS) IN (CDDDR MLE)
                   1922:              WHEN (ASSQ TYPE *SPECIALLY-COMBINED-METHOD-TYPES*)
                   1923:                APPEND FSPECS)
                   1924:        #'(LAMBDA (FS1 FS2)
                   1925:            (LOOP WITH FL1 = (CADR FS1) AND FL2 = (CADR FS2)
                   1926:                  FOR SUP IN (FLAVOR-DEPENDS-ON-ALL *FL*)
                   1927:                  WHEN (EQ SUP FL2) RETURN T    ;Base flavor earlier in list
                   1928:                  WHEN (EQ SUP FL1) RETURN NIL)))))
                   1929: 
                   1930: (DEFUN PUT-WRAPPER-INTO-COMBINED-METHOD (WRAPPER-NAME FORM)
                   1931:   (LET ((DEF (COND #-Franz ((DECLARED-DEFINITION WRAPPER-NAME))
                   1932:                   ;; What would the above mean in Franz?
                   1933:                   ((getd (method-function-name WRAPPER-NAME)))
                   1934:                   (T (FERROR () "~S supposed to be a wrapper macro, but missing!"
                   1935:                              WRAPPER-NAME)))))
                   1936:     (COND ((not (and (dtpr DEF)
                   1937:                     (eq (CAR DEF) 'MACRO)))
                   1938:           (FERROR () "~S, supposed to be a wrapper macro, is poorly formed. Definiton is ~s"
                   1939:                   WRAPPER-NAME DEF)))
                   1940:   ;; Here we just put the wrapper in as a macro.  It will be expanded by the compiler.
                   1941:     `(MACROCALL ,WRAPPER-NAME .DAEMON-CALLER-ARGS. ,FORM)))
                   1942: 
                   1943: ;Sort of a macro version of funcall, for wrappers
                   1944: (DEFMACRO MACROCALL (&REST X)
                   1945:   (LET ((MACRO (COND #-Franz ((DECLARED-DEFINITION (CAR X)))
                   1946:                     ((method-function-name (CAR X)))
                   1947:                     (T (FERROR () "Unable to find definition of wrapper ~s at expand time"
                   1948:                                (CAR X))))))
                   1949:     (IF (AND (LISTP MACRO) (EQ (CAR MACRO) 'MACRO))
                   1950:        (FUNCALL (cons 'lambda (CDR MACRO)) X)
                   1951:        ;--- Temporary code so I can test things in the kludge environment
                   1952:        (IF (AND (SYMBOLP MACRO) (LISTP (getd MACRO))
                   1953:                 (EQ (CAR (getd MACRO)) 'MACRO))
                   1954:            (FUNCALL (cons 'lambda (CDR (getd MACRO))) X)
                   1955:            (FERROR () "~S evaluated to ~S, which is not a macro"
                   1956:                    (CAR X) MACRO)))))
                   1957: 
                   1958: ;; Given a functional object, return its subfunction to do the given 
                   1959: ;; operation or NIL.   Returns NIL if it does not reduce to a select-method 
                   1960: ;; or if it does not handle that."
                   1961: (DEFUN GET-HANDLER-FOR (FUNCTION OPERATION &OPTIONAL (SUPERIORS-P T) &AUX TEM)
                   1962:   (COND ((SYMBOLP FUNCTION)
                   1963:         (COND ((SETQ TEM (GET FUNCTION 'FLAVOR))
                   1964:                (GET-FLAVOR-HANDLER-FOR TEM OPERATION))))
                   1965:        ((:TYPEP FUNCTION 'FLAVOR)
                   1966:         (GET-FLAVOR-HANDLER-FOR (FLAVOR-NAME FUNCTION) OPERATION))
                   1967:        ((INSTANCEP FUNCTION)
                   1968: ; SMH@EMS VVV
                   1969: ;       (GET-FLAVOR-HANDLER-FOR (FLAVOR-NAME (VREF FUNCTION 6))
                   1970: ;                               OPERATION)
                   1971:         (GET-FLAVOR-HANDLER-FOR
                   1972:          (FLAVOR-NAME (INT:FCLOSURE-STACK-STUFF (VREF FUNCTION 2)))
                   1973:                                 OPERATION)
                   1974: ; SMH@EMS ^^^
                   1975: )))
                   1976: 
                   1977: ;;; Get the function that would handle an operation for a flavor
                   1978: (DEFUN GET-FLAVOR-HANDLER-FOR (FLAVOR-NAME OPERATION &AUX FL)
                   1979:   (CHECK-ARG FLAVOR-NAME (SETQ FL (GET FLAVOR-NAME 'FLAVOR))
                   1980:             "the name of a flavor")
                   1981:   ;; Do any composition (compilation) of combined stuff, if not done already
                   1982:   (OR (FLAVOR-DEPENDS-ON-ALL FL) (COMPOSE-FLAVOR-COMBINATION FL))
                   1983:   (OR (FLAVOR-METHOD-HASH-TABLE FL) (COMPOSE-METHOD-COMBINATION FL))
                   1984:   (GETHASH OPERATION (FLAVOR-METHOD-HASH-TABLE FL)))
                   1985: 
                   1986: (DEFUN SYMEVAL-IN-INSTANCE (INSTANCE VAR)
                   1987:   (CHECK-ARG INSTANCE INSTANCEP "an instance")
                   1988:   (SYMEVAL-IN-FCLOSURE INSTANCE VAR))
                   1989: 
                   1990: (DEFSETF SYMEVAL-IN-INSTANCE (E V) `(SET-IN-INSTANCE ,(CADR E) ,(CADDR E) ,V))
                   1991: 
                   1992: (DEFUN SET-IN-INSTANCE (INSTANCE VAR VAL)
                   1993:   (CHECK-ARG INSTANCE INSTANCEP "an instance")
                   1994:   (SET-IN-FCLOSURE INSTANCE VAR VAL))
                   1995: 
                   1996: ;Interface to the compiler.
                   1997: (DEFUN COMPILE-AT-APPROPRIATE-TIME (FL NAME LAMBDA-EXP &OPTIONAL FORM-TO-EVAL)
                   1998:   (PUTD (METHOD-FUNCTION-NAME NAME)
                   1999:        (LAMBDACVT (CDR LAMBDA-EXP))))
                   2000: 
                   2001: ;This macro takes flavor names as "arguments".  It causes the compiler
                   2002: ;to include the appropriate methods in the qfasl file, provided all the
                   2003: ;component flavors are defined.
                   2004: (DEFMACRO COMPILE-FLAVOR-METHODS (&REST FLAVOR-NAMES)
                   2005:   `(PROGN 'COMPILE
                   2006:      (EVAL-WHEN (COMPILE)
                   2007:        . ,(MAPCAN #'(LAMBDA (FLAVOR-NAME)
                   2008:                      (NCONC (AND (GET FLAVOR-NAME 'FLAVOR)
                   2009:                                  (NCONS `(PUTPROP (FLAVOR-PLIST
                   2010:                                                    (GET ',FLAVOR-NAME 'FLAVOR))
                   2011:                                                   T
                   2012:                                                   'COMPILE-FLAVOR-METHODS)))
                   2013:                             (NCONS `(COMPILE-FLAVOR-METHODS-1 ',FLAVOR-NAME))))
                   2014:                  FLAVOR-NAMES))
                   2015:      (EVAL-WHEN (LOAD EVAL)
                   2016:        . ,(MAPCAR #'(LAMBDA (FLAVOR-NAME) `(COMPILE-FLAVOR-METHODS-2 ',FLAVOR-NAME))
                   2017:                  FLAVOR-NAMES))))
                   2018: 
                   2019: ;; Cause the combined-methods to get compiled.
                   2020: ;; Executed only from the compiler, and does something
                   2021: ;; only if compiling to a file.
                   2022: (DEFUN COMPILE-FLAVOR-METHODS-1 (FLAVOR-NAME &AUX FL)
                   2023:   (IF (JUST-COMPILING)
                   2024:       (LET ((*JUST-COMPILING* T)
                   2025:            (*USE-OLD-COMBINED-METHODS* NIL))
                   2026:        (COND ((FLAVOR-COMPONENTS-DEFINED-P FLAVOR-NAME 'COMPILE-FLAVOR-METHODS)
                   2027:               (SETQ FL (GET-FLAVOR FLAVOR-NAME))
                   2028:               ;; Make sure we are not hacking the installed flavor object,
                   2029:               ;; in case there is no defflavor or defmethod for the flavor in this file.
                   2030:               (AND (EQ FL (GET FLAVOR-NAME 'FLAVOR))
                   2031:                    (COMPILATION-DEFINE-FLAVOR
                   2032:                      FLAVOR-NAME
                   2033:                      (SETQ FL (FLAVOR-REDEFINITION-FOR-COMPILATION FL NIL))))
                   2034:               (OR (FLAVOR-DEPENDS-ON-ALL FL)
                   2035:                   (COMPOSE-FLAVOR-COMBINATION FL))
                   2036:               (COMPOSE-METHOD-COMBINATION FL NIL))))))
                   2037: 
                   2038: ;; Do the composition now.  This should normally just generate data-structure
                   2039: ;; as the methods should already all have been compiled, unless something has changed.
                   2040: (DEFUN COMPILE-FLAVOR-METHODS-2 (FLAVOR-NAME &AUX FL)
                   2041:   (CHECK-ARG FLAVOR-NAME (SETQ FL (GET FLAVOR-NAME 'FLAVOR)) "the name of a flavor")
                   2042:   (PUTPROP (FLAVOR-PLIST FL) T 'COMPILE-FLAVOR-METHODS)
                   2043:   (COND ((FLAVOR-COMPONENTS-DEFINED-P FLAVOR-NAME)
                   2044:         (OR (FLAVOR-DEPENDS-ON-ALL FL) (COMPOSE-FLAVOR-COMBINATION FL))
                   2045:         (OR (FLAVOR-METHOD-HASH-TABLE FL)
                   2046:             (COMPOSE-METHOD-COMBINATION FL))))
                   2047:   FLAVOR-NAME)
                   2048: 
                   2049: ;Returns T if all components of this flavor are defined
                   2050: (DEFUN FLAVOR-COMPONENTS-DEFINED-P (FLAVOR-NAME &OPTIONAL COMPLAINT &AUX FL)
                   2051:   (COND ((SETQ FL (GET-FLAVOR FLAVOR-NAME))
                   2052:         (OR (NOT (NULL (FLAVOR-DEPENDS-ON-ALL FL)))    ;Already composed, be fast
                   2053:             (AND (DO ((L (FLAVOR-DEPENDS-ON FL) (CDR L))) ((NULL L) T)
                   2054:                    (OR (FLAVOR-COMPONENTS-DEFINED-P (CAR L)) (RETURN NIL)))
                   2055:                  (DO ((L (FLAVOR-INCLUDES FL) (CDR L))) ((NULL L) T)
                   2056:                    (OR (FLAVOR-COMPONENTS-DEFINED-P (CAR L)) (RETURN NIL))))))
                   2057:        (COMPLAINT (FORMAT ERRPORT "~&~A - ~S undefined flavor" COMPLAINT FLAVOR-NAME)
                   2058:                   NIL)
                   2059:        (T NIL)))
                   2060: 
                   2061: (EVAL-WHEN (EVAL LOAD) (LOAD 'VANILLA))
                   2062: 
                   2063: ;; Local Modes:
                   2064: ;; Mode: Lisp
                   2065: ;; Case Search: 1
                   2066: ;; End:

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.