4.3BSD/usr/lib/lisp/flavorm.l

;; (c) Copywrite 1983, Massachusetts Institute of Technology
(setq rcs-flavorm-
   "$Header: flavorm.l,v 1.2 85/03/24 11:25:34 sklower Exp $")

;; This file contains some of the support macros that are need by the
;; flavor system.

(environment-maclisp)
(declare (macros t))

; The data-structure on the FLAVOR property of a flavor-name
(DEFSTRUCT (FLAVOR :NAMED)
  FLAVOR-BINDINGS		;List of locatives to instance variable
				; internal value cells.  MUST BE CDR-CODED!!
				;Fixnums can also appear.  They say to skip
				;whatever number of instance variable slots.
  FLAVOR-METHOD-HASH-TABLE	;The hash table for methods of this flavor.
				; NIL means method-combination not composed yet.
  FLAVOR-NAME			;Symbol which is the name of the flavor.
				; This is returned by TYPEP.
  FLAVOR-LOCAL-INSTANCE-VARIABLES	;Names and initializations,
					; does not include inherited ones.
  FLAVOR-ALL-INSTANCE-VARIABLES	;Just names, only valid when "flavor 
				; combination" composed.  Corresponds directly
				; to FLAVOR-BINDINGS and the instances.
  FLAVOR-METHOD-TABLE		;Defined below.
  ;; End of locations depended on in many other files.
  FLAVOR-DEPENDS-ON		;List of names of flavors incorporated into this flavor.
  FLAVOR-DEPENDED-ON-BY		;List of names of flavors which incorporate this one.
				;The above are only immediate dependencies.
  FLAVOR-INCLUDES		;List of names of flavors to include at the end
				; rather than as immediate depends-on's.
  FLAVOR-DEPENDS-ON-ALL		;Names of all flavors depended on, to all levels, including
				; this flavor itself.  NIL means flavor-combination not
				; composed yet.  This is used by TYPEP of 2 arguments.
  (FLAVOR-WHICH-OPERATIONS NIL)	;List of operations handled, created when needed.
				; This is NIL if it has not been computed yet.
  ;; Redundant copy of :DEFAULT-HANDLER property, for speed in calling it.
  (FLAVOR-DEFAULT-HANDLER NIL)
  (FLAVOR-GETTABLE-INSTANCE-VARIABLES NIL)
  (FLAVOR-SETTABLE-INSTANCE-VARIABLES NIL)
  (FLAVOR-INITABLE-INSTANCE-VARIABLES NIL)
				;Alist from init keyword to name of variable
  (FLAVOR-INIT-KEYWORDS NIL)			;option
  (FLAVOR-PLIST NIL)		;Esoteric things stored here as properties
				;Known: :ORDERED-INSTANCE-VARIABLES, :DEFAULT-HANDLER
				; :OUTSIDE-ACCESSIBLE-INSTANCE-VARIABLES, :ACCESSOR-PREFIX,
				; :REQUIRED-INSTANCE-VARIABLES, :REQUIRED-METHODS,
				; :REQUIRED-FLAVORS, :SELECT-METHOD-ORDER,
				; :DEFAULT-INIT-PLIST, :DOCUMENTATION, :NO-VANILLA-FLAVOR
				; :GETTABLE-INSTANCE-VARIABLES :SETTABLE-INSTANCE-VARIABLES
				; ADDITIONAL-INSTANCE-VARIABLES
				; COMPILE-FLAVOR-METHODS
				; MAPPED-COMPONENT-FLAVORS
				; INSTANCE-VARIABLE-INITIALIZATIONS
				; ALL-INITABLE-INSTANCE-VARIABLES
				; REMAINING-DEFAULT-PLIST
				; REMAINING-INIT-KEYWORDS
				;The convention on these is supposed to be that
				;ones in the keyword packages are allowed to be
				;used by users.
				;Some of these are not used by the flavor system, they are
				;just remembered on the plist in case anyone cares.  The
				;flavor system does all its handling of them during the
				;expansion of the DEFFLAVOR macro.
  )

(defsubst instancep (x)
  (and (fclosurep x) (eq (fclosure-function x) #'flavor-dispatch)))

(defvar self ()
  "Self referential pointer for flavors")

(defmacro send (object message &rest args) 
  (if (eq object 'self)
      `(send-self ,message ,@args)
      `(send-internal ,object ,message ,@args)))

(defmacro lexpr-send (object &rest args)
  (if (eq object 'self)
      `(lexpr-send-self ,@args)
      `(lexpr-funcall #'send-internal ,object ,@args)))

;; These two functions are used when sending a message to yourself, for 
;; extra efficiency.  They avoid the variable unbinding and binding 
;; required when entering a closure.
(defmacro send-self (message &rest args)
  `(funcall (or (gethash ,message (flavor-method-hash-table .own-flavor.))
		(flavor-default-handler .own-flavor.))
	    ,message . ,args))
(defmacro funcall-self (&rest args) `(send-self . ,args))

(defmacro lexpr-send-self (message &rest args)
  `(lexpr-funcall (or (gethash ,message
			       (flavor-method-hash-table .own-flavor.))
		      (flavor-default-handler .own-flavor.))
		  ,message . ,args))
(defmacro lexpr-funcall-self (&rest args) `(lexpr-send-self . ,args))

(defsetf send (e v)
  (if (or (atom (caddr e))
	  (neq (car (caddr e)) 'quote))
      (ferror () "Don't know how to setf this ~S" e))
  (cond ((eq (cadr (caddr e)) ':get)
	 `(send ,(cadr e) ':putprop ,v ,(cadddr e)))
	(t
	 `(send ,(cadr e) ',(intern (format () ":set-~A"
					    (remove-colon (cadr (caddr e)))))
			  ,v))))

(putprop 'flavorm t 'version)