[comp.sources.unix] v10i081: Common Ojbects, Common Loops, Common Lisp, Part07/13

rs@uunet.UU.NET (Rich Salz) (08/03/87)

Submitted-by: Roy D'Souza <dsouza%hplabsc@hplabs.HP.COM>
Posting-number: Volume 10, Issue 81
Archive-name: comobj.lisp/Part07

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 7 (of 13)."
# Contents:  co-dmeth.l macros.l
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'co-dmeth.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'co-dmeth.l'\"
else
echo shar: Extracting \"'co-dmeth.l'\" \(22335 characters\)
sed "s/^X//" >'co-dmeth.l' <<'END_OF_FILE'
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X;
X; File:         co-dmeth.l
X; RCS:          $Revision: 1.1 $
X; SCCS:         %A% %G% %U%
X; Description:  Defining CommonObjects methods
X; Author:       James Kempf
X; Created:      March 10, 1987
X; Modified:     12-Mar-87 09:21:38 (James Kempf)
X; Language:     Lisp
X; Package:      COMMON-OBJECTS
X; Status:       Distribution
X;
X; (c) Copyright 1987, HP Labs, all rights reserved.
X;
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X;
X; Copyright (c) 1987 Hewlett-Packard Corporation. All rights reserved.
X;
X; Use and copying of this software and preparation of derivative works based
X; upon this software are permitted.  Any distribution of this software or
X; derivative works must comply with all applicable United States export
X; control laws.
X; 
X; This software is made available AS IS, and Hewlett-Packard Corporation makes
X; no warranty about the software, its performance or its conformity to any
X; specification.
X;
X; Suggestions, comments and requests for improvement may be mailed to
X; aiws@hplabs.HP.COM
X
X;;;-*-Mode:LISP; Package:(CO (PCL LISP)); Base:10; Syntax: Common-lisp-*-
X;;;
X;;; *************************************************************************
X;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
X;;;
X;;; Use and copying of this software and preparation of derivative works
X;;; based upon this software are permitted.  Any distribution of this
X;;; software or derivative works must comply with all applicable United
X;;; States export control laws.
X;;; 
X;;; This software is made available AS IS, and Xerox Corporation makes no
X;;; warranty about the software, its performance or its conformity to any
X;;; specification.
X;;; 
X;;; Any person obtaining a copy of this software is requested to send their
X;;; name and post office or electronic mail address to:
X;;;   CommonLoops Coordinator
X;;;   Xerox Artifical Intelligence Systems
X;;;   2400 Hanover St.
X;;;   Palo Alto, CA 94303
X;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
X;;;
X;;; Suggestions, comments and requests for improvements are also welcome.
X;;; *************************************************************************
X
X(in-package 'common-objects :nicknames '(co) :use '(lisp pcl walker))
X
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X; 
X;  nued) Support for Using Keywords as Method Names
X;
X;  These macros and functions translate keyword method names into
X;  names in a package. Some Common Lisps do allow keyword symbols
X;  to have an associated function, others don't. Rather than
X;  differentiating, a single package, KEYWORD-STANDIN, is used
X;  for method symbols which are keywords.
X;
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X
X(defun keyword-standin (keyword)
X
X  ;;An example of a special method is :print which gets
X  ;;  translated into the symbol pcl:print-instance
X
X  (if (special-keyword-p keyword)
X    (keyword-standin-special keyword)
X    (intern (symbol-name keyword) *keyword-standin-package*)
X  )
X
X) ;end keyword-standin
X
X;;unkeyword-standin-Return the keyword for a standin symbol
X
X(defun unkeyword-standin (symbol)
X  
X  (if (special-method-p symbol)
X    (unkeyword-standin-special symbol)
X      (if (eq (symbol-package symbol) *keyword-standin-package*)
X	(setf symbol (intern (symbol-name symbol) (find-package :keyword)))
X	symbol
X
X       ) ;if
X
X  ) ;if
X
X) ;end unkeyword-standin
X
X;;Set up the universal method selector list, for fast messaging
X
X(eval-when (load eval)
X  (dolist (l *universal-methods*)
X    (push (keyword-standin l) *universal-method-selectors*)
X  )
X)
X
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X; 
X;	Runtime Interface to the Slots
X;
X;  The extra slots are used for the pointer to self and for parents. Each 
X;  ancestor is actually a fully fledged object of the ancestor type, except its 
X;  pointer to self slot points back to the original object piece.
X;  Slot indicies can be calculated directly at compile time, since they do
X;  not change after the object is created.
X;
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X
X;;self-from-inner-self-Return the pointer to the original object
X
X(defmacro self-from-inner-self ()
X  `(%instance-ref .inner-self. ,$SELF-INDEX)
X
X) ;end self-from-inner-self
X
X;;parent-from-inner-self-Given the parent's name, return a pointer
X;;  to the object piece in which the instance variables are stored.
X
X(defmacro parent-from-inner-self (parent-class-name)
X  `(get-slot .inner-self. ',(local-super-slot-name parent-class-name))
X
X) ;end parent-from-inner-self
X
X;;local-super-slot-name-Generate a slot name for the parent's instance
X;;  variable
X
X(defun local-super-slot-name (local-super-name)
X  (intern (concatenate 'string
X		"Slot For "
X		    (symbol-name local-super-name)))
X
X) ;end local-super-slot-name
X
X;;calculate-slot-index-Return the index of the slot in the vector
X
X(defun calculate-slot-index (slotname parents slots)
X
X  (let
X    (
X      (parloc (position slotname parents))
X      (sloc  (position slotname slots))
X    )
X
X    (if parloc
X     (+ $START-OF-PARENTS parloc)
X     (+ $START-OF-PARENTS (length parents) sloc)
X    )
X
X  )
X
X)
X
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X; 
X;	New Method Class For CommonObjects
X;
X;  CommonObjects methods need to keep track of their method symbol, so
X;  that the symbol can be looked up and inserted into a CALL-METHOD
X;  or APPLY-METHOD when a method including one of these forms is loaded.
X;  The new method keeps track of a method symbol as an instance variable,
X;  and maintains the symbol's function cell with an accurate pointer to
X;  the current function implementing the method. The function is called
X;  through this symbol during run-time processing of a CALL-METHOD.
X;  Note that, since the method object gets created when the method
X;  is loaded (or, alternatively, looked up, if a CALL-METHOD was
X;  processed before the method was defined), the symbol will be GENSYM'ed
X;  in the load time environment. Fully qualified symbols are needed for
X;  the method names because they are not exported from the PCL package.
X;
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X
X;;common-objects-method-Add an additional slot for the function symbol name
X
X(ndefstruct 
X  (common-objects-method (:class class) 
X    (:include pcl::method)
X    (:conc-name method-)
X  )
X    (function-symbol NIL)	;;name of the method function
X				;;  used for call-method
X
X) ;end common-objects-method
X
X;;method-function-Need this to have the SETF
X;;  method work correctly
X
X(defmeth method-function  ((method common-objects-method))
X
X  ;;This was RUN-SUPER-INTERNAL, but now changed to accomodate
X  ;;  new code.
X
X  (call-next-method)
X
X
X) ;end method-function
X
X;;method-function-Even though we may not yet be able to
X;;  determine what the function symbol is, the SETF method
X;;  must reset the symbol's function, in the event the
X;;  method object is recycled. 
X
X(defmeth (method-function (:setf (nv))) ((method common-objects-method))
X
X
X    ;;If the method function symbol for the CALL-METHOD optimization
X    ;;  has not yet been set, do it.
X
X    (when (method-function-symbol method)
X      (setf (symbol-function (method-function-symbol method)) 
X	    nv
X      )
X
X    )
X
X
X    ;;This was RUN-SUPER-INTERNAL, but now changed to accomodate
X    ;; new code.
X
X    (call-next-method)
X
X) ;end method-function :setf
X
X;;method-discriminator-Need this to have the SETF
X;;  method work correctly
X
X(defmeth method-discriminator  ((method common-objects-method))
X
X  ;;This was RUN-SUPER-INTERNAL, but now changed to accomodate
X  ;;  new code.
X
X  (call-next-method)
X
X
X) ;end method-discriminator
X
X;;method-discriminator-By the time the method's discriminator is
X;;  set, the method has enough information to generate the
X;;  symbol for CALL-METHOD optimization.
X
X(defmeth (method-discriminator (:setf (nv))) ((method common-objects-method))
X
X
X    ;;If the method function symbol for the CALL-METHOD optimization
X    ;;  has not yet been set, do it.
X
X    (when (not (method-function-symbol method))
X      (setf (method-function-symbol method) 
X            (generate-method-function-symbol
X	      (class-name (car (method-type-specifiers method)))
X	      (discriminator-name nv)
X	    )
X      )
X      (setf (symbol-function (method-function-symbol method)) 
X	    (method-function method)
X      )
X
X    )
X
X
X    ;;This was RUN-SUPER-INTERNAL, but now changed to accomodate
X    ;; new code.
X
X    (call-next-method)
X
X) ;end method-discriminator :setf
X
X;;generate-method-function-symbol-Generate a method function
X;;  symbol for the method. Used in the CALL-METHOD optimization.
X
X(defun generate-method-function-symbol (class-name message)
X
X  ;;Generate a symbol for the function to be called.
X  ;;  This is in the same package as the method name
X  ;;  symbol, and its name as the form:
X  ;;  <class package name>;;<class name> <message package name>;;<message>
X  ;;  Note that this will avoid collisions for two methods with
X  ;;  the same name and different packages, because the symbol
X  ;;  names (as well as the packages) are different.
X  ;;  We hope that this should avoid collision.
X
X  (intern
X    (concatenate 'simple-string 
X		 (package-name (symbol-package class-name))
X		 ";;"
X		 (symbol-name class-name)
X		 " " 
X		 (package-name     
X		   (if (keywordp message)
X                     (find-package 'keyword-standin)
X                     (symbol-package message)
X                   )
X                 )
X		 ";;"
X		 (symbol-name message)
X    )
X    (if (keywordp message)
X      (find-package 'keyword-standin)
X      (symbol-package message)
X    )
X ) 
X
X) ;generate-method-function-symbol
X
X;;expand-with-make-entries-Returns an alist of the form:
X;; 
X;;   (<prefix+slot-name> <instance-form> <class> <slotd> <use-slot-value-p>)
X;;
X
X(defmeth expand-with-make-entries ((method common-objects-method) first-arg)
X         (declare (ignore first-arg))   ; rds 3/8
X  (let* 
X    (
X      (entries ())
X      (method-argument (first (method-arglist method)))
X      (method-type-spec (first (method-type-specifiers method)))
X    )          
X
X    ;;CommonObjects methods only discriminate on the first 
X    ;;  argument. Also, we always want to use the slot value,
X    ;;  since there is no slotd-accessor.
X
X    (dolist (slotd (class-slots method-type-spec))
X      (push
X        (list
X          (slotd-name slotd)	;;the slot name
X          method-argument	;;the instance arg name
X          method-type-spec	;;the class
X          slotd			;;the slot descriptor
X          T              	;;use the slot value directly
X        )
X        entries
X      )
X    ) ;dolist
X
X    entries
X
X  ) ;let*
X
X) ;expand-with-make-entries
X
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X;              Messaging Macros and Functions
X;
X;   Message sending becomes funcalling the message.
X;   We convert all message sends to a funcall of the message.  Because
X;   CommonObjects encourages messages to be keywords and keywords are
X;   not funcallable, we have to have a special package in which keywords
X;   are interned before their use as messages.
X;
X;   As an example of all this, take the expansion of a sample =>:
X;
X;      (=> object :message arg-1 arg-2)  expands into:
X;
X;      (funcall 'keyword-standin::message object arg-1 arg-2)
X;
X;   This means that all CommonObjects discriminators will be classical.
X;   That is they will discriminator only on the class of their first
X;   argument.
X; 
X;   The first argument to any method will always be the inner self, that is
X;   an instance of the same class as the method was defined on.  This is
X;   bound to the symbol .INNER-SELF., special macros SELF-FROM-INNER-SELF
X;   and PARENT-FROM-INNER-SELF are used to access outer-self and parent
X;   instances.
X;
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X
X;;make-set-message-Construct a :SET-xxx message for SETF
X
X(defmacro make-set-message (message)
X  
X  `(intern
X    (concatenate 'simple-string 
X                 "SET-" 
X                 (symbol-name ,message)
X    )
X    (symbol-package ,message)
X
X  )
X
X) ;make-set-message
X
X;;=>-Convert to PCL messaging. Note that no error or type checking occurs.
X
X(defmacro => (object message &rest args)
X
X  `(funcall
X      ,(if (keywordp message)
X	`',(keyword-standin message)
X        message
X      )
X      ,object 
X      ,@args
X  )
X
X) ;end =>
X
X;;send?-Messaging macro which returns NIL if something is wrong.
X
X(defmacro send? (object message &rest args)
X
X  `(send?-internal 
X    ,object 
X    ,(if (keywordp message)
X	`',(keyword-standin message)
X	 message
X    )  
X    ,@args
X  )
X
X) ;end send?
X
X;;Setf definitions for messaging macros.
X
X(defsetf => (obj message) (new-value)
X
X  `(progn
X      (=> ,obj 
X          ,(if (keywordp message)
X            (make-set-message message)
X            `(make-set-message ,message)
X          )
X	  ,new-value
X      )
X    )
X) ;end defsetf for =>
X
X(defsetf send? (obj message) (new-value)
X  `(progn
X      (send? ,obj 
X             ,(if (keywordp message)
X               (make-set-message message)
X               `(make-set-message ,message)
X              )
X	    ,new-value
X      )
X    )
X) ;end defsetf for send?
X
X;;send?-internal-Process the message invocation into correct code for
X;; SEND?
X
X(defun send?-internal (object message &rest args)
X
X  (if object
X    (let*
X       (
X         (class (class-of object))
X         (class-name (class-name class))
X         (metaclass-name (class-name (class-of class)))
X
X       )
X
X      ;;Check if OBJECT is an instance and class is still defined
X      ;;  and operation is supported.
X
X      (if (and
X           (eq metaclass-name 'common-objects-class)
X           (not (eq class-name $UNDEFINED-TYPE-NAME))
X           (fast-supports-operation-p class message)
X          )
X
X    	  (apply message  object args)
X
X          NIL
X
X      ) ;if
X
X    ) ;let*
X
X  ) ;if
X
X) ;send?-internal
X
X;;fast-supports-operation-p-Does no checking on CLASS
X
X(defun fast-supports-operation-p (class message)
X
X;;Check first if its a universal method
X
X  (if (member (unkeyword-standin message) *universal-methods*)
X
X    T
X
X    ;;Otherwise, check in the class object if it's got them
X
X    (dolist (methobj (pcl::class-direct-methods class))
X
X      (when (eq (method-name methobj) message)
X        (return-from fast-supports-operation-p T)
X      )
X
X    ) ;dolist
X  ) ;if
X
X) ;fast-supports-operation-p
X
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X;  Method Definition
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X
X;;defcommon-objects-meth-Create method and discriminator objects and
X;;  call EXPAND-DEFMETH-INTERNAL. The method object is of class
X;;  common-objects-method. Note that this macro gets expanded at the
X;;  time this file is compiled.
X
X(defmacro defcommon-objects-meth (message arglist body)
X
X
X  `(let 
X    (
X      (discriminator-class-object (class-named 'pcl::discriminator t))
X      (method-class-object (class-named 'common-objects-method t))
X    )
X
X    (pcl::expand-defmeth-internal (class-prototype discriminator-class-object)
X			          (class-prototype method-class-object)
X			          (if (listp ,message) ,message (list ,message))
X			          ,arglist
X			          (list ,body)
X    )
X
X  ) ;let
X
X) ;end defcommon-objects-meth
X
X;;define-method-Top level programmer interface to method
X;;  definition
X
X(defmacro define-method (spec arglist &body body)
X
X  ;;Syntax check the call first
X
X  (co-parse-method-macro-call spec arglist body)
X
X  (let* 
X    (
X      (class-name (car spec))
X      (message (if (keywordp (cadr spec))
X		     (keyword-standin (cadr spec))
X		     (cadr spec)))
X    )
X
X
X    ;;Check first to be sure that class is a CommonObjects class
X
X    (if (not 
X          (eq (class-name (class-of (class-named class-name T))) 'common-objects-class)
X        )
X      (error "DEFINE-METHOD: `~S' is not a CommonObjects type." class-name)
X    )
X
X    ;;The compiler-let of *CURRENT-METHOD-CLASS-NAME* is to support
X    ;;  CALL-METHOD.
X    ;;  Also, bind SELF around the body to outer self.
X    ;;  Note that this allows someone to rebind SELF in the body, but
X    ;;  that rebinding will not affect CALL-METHOD, APPLY-METHOD or IV
X    ;;  access since they don't really use SELF.
X    ;;  Also, use WITH to allow lexical access to the instance 
X    ;;  variables.
X
X    (setq body `(compiler-let 
X                  (
X                    (*current-method-class-name* ',class-name)
X	          )
X
X                  (let ((self (self-from-inner-self)))
X		    (with* 
X		      (
X			(.inner-self. "" ,class-name)
X		      )
X
X                      self
X		      (progn . ,body))
X                 )
X
X	      ) ;compiler-let
X    )	  
X
X
X    `(progn
X
X        ,(defcommon-objects-meth message 
X           `((.inner-self. ,class-name) ,@arglist) 
X
X	   body
X
X         )
X
X         (list ',class-name ',(cadr spec))
X
X       ) ;progn
X
X   ) ;let*
X
X) ;end define-method
X
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X; 
X;	Call-Method and Optimizations
X;
X;  Because of pf the ambiguous nature of the definition of #, in CLtL,
X;  the implementation of #, may not work correctly on a particular system
X;  when used within the backquote macro in compiled code.
X;  The kind of behavior which is needed is as follows (with reference
X;  to 5.3.3, pg. 70)
X;
X;  1) If the situation is EVAL, then execute the function
X;     LOAD-TIME-GET-CALL-METHOD-FUNCTION-SYMBOL and cache the 
X;     method symbol in line when the code is macroexpanded.
X;
X;  2) If the situation is compile, then arrange for the function
X;     LOAD-TIME-GET-CALL-METHOD-FUNCTION-SYMBOL to be executed
X;     and the result cached only when the file gets loaded.
X;
X;  What I want to say is:
X;
X;   `(,caller
X;         #,(load-time-get-call-method-function ',class-name ',method-name
X;					       ',arglist
X;          )
X;          <rest of form>
X;     )
X;
X;  and have it work correctly. Well, it doesn't always.
X;
X;  Alternatively, I would like to generate a closure at compile time
X;  which will get fasled into the output file and will cache the
X;  method symbol the first time it is called. But that doesn't
X;  always work either.
X;
X;  So, instead, I tried using an elaborate scheme which creates vectors
X;  at compile time and uses a top level (EVAL-WHEN (LOAD) ...) to 
X;  depost the method symbol at load time. The special variable
X;  *LIST-OF-CALL-METHOD-FIXUPS* gets bound to NIL before every
X;  DEFINE-METHOD invocation. The CALL-METHOD macro creates
X;  instances of the DEFSTRUCT CALL-METHOD-RECORD and pushes them
X;  on *LIST-OF-CALL-METHOD-FIXUPS* recording CALL-METHODs and
X;  vectors for caching the method symbol. The CALL-METHOD macro
X;  can do this because the PCL method EXPAND-DEFMETH-INTERNAL
X;  is replaced in the patches file. This new method walks
X;  them method code body during the execution of EXPAND-DEFMETH-INTERNAL
X;  rather than at the top level, as in the stock PCL system.
X;  If this change is NOT made, then the method body must
X;  be prewalked before code generation, because the code
X;  walk (during which CALL-METHOD gets expanded) doesn't
X;  occur until after DEFINE-METHOD returns to the top level.
X;
X;  As the last part of the DEFINE-METHOD code generation,
X;  a top level (EVAL-WHEN (LOAD EVAL) ...) is generated to get
X;  the method symbol at load time and deposit it in the
X;  vector. The SVREF gets the symbol at the time the CALL-METHOD
X;  is invoked. So, in effect, I'm generating my own
X;  closure.
X;
X;  Well, that doesn't work either. Why? Because once the
X;  vector is deposited into the code, there is no guarantee
X;  that it will be EQ to the one in the list. And, in any
X;  event, this scheme won't work in traditional interpreters
X;  which expand macros as they are encountered, since the
X;  top level (EVAL-WHEN (LOAD EVAL) ... ) gets done before
X;  the CALL-METHOD macro is fully expanded.
X;
X;  Sigh. The only choice is to GENSYM a symbol at compile
X;  time and pray that it doesn't trash something at load time.
X;  But maybe that's OK.
X;
X;  Note that the general behavior which is desired here is loadtime 
X;  execution within generated code, rather than at the top level.
X;
X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
X
X;;call-method-Top level macro for CALL-METHOD.
X
X(defmacro call-method (spec &rest args)
X  (call-method-internal 'call-method spec args) 
X
X) ;end call-method
X
X;;apply-method-Top level macro for APPLY-METHOD.
X
X(defmacro apply-method (spec &rest args)
X  (call-method-internal 'apply-method spec args)
X
X) ;end apply-method
X
X;;call-method-internal-Process a CALL-METHOD invocation.
X
X(defun call-method-internal (for spec args)
X  (declare (special *current-method-class-name*))
X  (if (null (boundp '*current-method-class-name*))
X      (error "Attempt to use ~S other than inside a method.~%" for)
X      (let* ((caller (ecase for
X		      (call-method 'funcall)
X		      (apply-method 'apply)))
X	    (class-name (if (listp spec)
X			    (car spec)
X			    *current-method-class-name*))
X	    (message (if (listp spec) (cadr spec) spec))
X
X	    (fsym (generate-method-function-symbol class-name message))
X
X          )
X
X
X         ;;Check the syntax
X
X         (co-parse-call-to-method (list for spec args) 
X                                  (symbol-name for)
X                                  *current-method-class-name*
X         )
X
X
X         ;;Generate code. Note there is no need to check
X         ;;  whether or not the method function symbol
X         ;;  is bound or to do any fixing up at all.
X         ;;  If it is not, then its an error, because
X         ;;  the method hasn't yet been defined. The
X         ;;  function cell will be bound when the 
X         ;;  method gets defined.
X
X	`(,caller (symbol-function ',fsym)
X
X	  ,(if (listp spec)
X	       `(parent-from-inner-self ,class-name)
X	       '.inner-self.)
X	  ,@args)
X    ) ;let
X  ) ;if
X
X) ;end call-method-internal
X
X
X;;legal-parent-p-Is parent-name a legal parent of class-name?
X
X(defun legal-parent-p (class-name parent-name)
X
X  (member parent-name 
X          (class-local-super-names (class-named class-name T))
X          :test #'eq
X
X  )
X) ;legal-parent-p
X
X
END_OF_FILE
if test 22335 -ne `wc -c <'co-dmeth.l'`; then
    echo shar: \"'co-dmeth.l'\" unpacked with wrong size!
fi
# end of 'co-dmeth.l'
fi
if test -f 'macros.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'macros.l'\"
else
echo shar: Extracting \"'macros.l'\" \(25561 characters\)
sed "s/^X//" >'macros.l' <<'END_OF_FILE'
X;;;-*-Mode:LISP; Package:(PCL (LISP WALKER)); Base:10; Syntax:Common-lisp -*-
X;;;
X;;; *************************************************************************
X;;; Copyright (c) 1985 Xerox Corporation.  All rights reserved.
X;;;
X;;; Use and copying of this software and preparation of derivative works
X;;; based upon this software are permitted.  Any distribution of this
X;;; software or derivative works must comply with all applicable United
X;;; States export control laws.
X;;; 
X;;; This software is made available AS IS, and Xerox Corporation makes no
X;;; warranty about the software, its performance or its conformity to any
X;;; specification.
X;;; 
X;;; Any person obtaining a copy of this software is requested to send their
X;;; name and post office or electronic mail address to:
X;;;   CommonLoops Coordinator
X;;;   Xerox Artifical Intelligence Systems
X;;;   2400 Hanover St.
X;;;   Palo Alto, CA 94303
X;;; (or send Arpanet mail to CommonLoops-Coordinator.pa@Xerox.arpa)
X;;;
X;;; Suggestions, comments and requests for improvements are also welcome.
X;;; *************************************************************************
X;;;
X;;; Macros global variable definitions, and other random support stuff used
X;;; by the rest of the system.
X;;;
X;;; For simplicity (not having to use eval-when a lot), this file must be
X;;; loaded before it can be compiled.
X;;;
X
X(in-package 'pcl :nicknames '(portable-commonloops) :use '(lisp walker))
X
X(export '(defclass
X	  defmethod
X	  print-object
X
X	  print-instance
X	  ndefstruct
X	  defmeth
X	  run-super
X	  make
X	  initialize
X	  get-slot
X	  with
X	  with*
X	  class-of
X	  class-named
X	  discriminator-named
X	  class-prototype
X	  class
X	  object
X
X
X
X	  essential-class
X	  
X	  class-name
X	  class-precedence-list
X	  class-local-supers
X	  class-local-slots
X	  class-direct-subclasses
X	  class-direct-methods
X	  class-slots
X
X
X	  essential-discriminator
X
X	  discriminator-name
X	  discriminator-methods
X	  discriminator-discriminating-function
X
X	  essential-method
X
X	  method-discriminator
X	  method-arglist
X	  method-argument-specifiers			
X	  method-function
X
X	  method-equal
X
X	  discriminator-methods
X
X	  slotd-name
X	  slot-missing
X
X	  define-meta-class
X	  %make-instance
X	  %instance-ref
X	  %instancep
X	  %instance-meta-class
X
X	  make-instance
X	  get-slot
X	  put-slot
X	  get-slot-using-class
X	  optimize-slot-access
X	  define-class-of-clause
X	  add-named-class
X	  class-for-redefinition
X	  add-class
X	  supers-changed
X	  slots-changed
X	  check-super-meta-class-compatibility
X	  check-meta-class-change-compatibility
X	  make-slotd
X	  compute-class-precedence-list
X	  walk-method-body
X	  walk-method-body-form
X	  optimize-get-slot
X	  optimize-set-of-get-slot
X	  variable-lexical-p
X	  add-named-method
X	  add-method
X	  remove-named-method
X	  remove-method
X	  find-method
X	  find-method-internal
X	  make-discriminating-function
X	  install-discriminating-function
X	  no-matching-method
X	  class-class-precedence-list
X	  class-local-supers
X	  class-direct-subclasses
X	  class-name
X	  
X	  )
X	(find-package 'pcl))
X
X(proclaim '(declaration values			;I use this so that Zwei can
X						;remind me what values a
X						;function returns.
X			
X			method-function-name	;This is used so that some
X						;systems can print the name
X						;of the method when I am in
X						;the debugger.
X                        ))
X
X;;; Age old functions which CommonLisp cleaned-up away.  They probably exist
X;;; in other packages in all CommonLisp implementations, but I will leave it
X;;; to the compiler to optimize into calls to them.
X;;;
X;;; Common Lisp BUG:
X;;;    Some Common Lisps define these in the Lisp package which causes
X;;;    all sorts of lossage.  Common Lisp should explictly specify which
X;;;    symbols appear in the Lisp package.
X;;;    
X(defmacro memq (item list) `(member ,item ,list :test #'eq))
X(defmacro assq (item list) `(assoc ,item ,list :test #'eq))
X(defmacro rassq (item list) `(rassoc ,item ,list :test #'eq))
X(defmacro delq (item list) `(delete ,item ,list :test #'eq))
X(defmacro neq (x y) `(not (eq ,x ,y)))
X
X(defun make-caxr (n form)
X  (if (< n 4)
X      `(,(nth n '(car cadr caddr cadddr)) ,form)
X      (make-caxr (- n 4) `(cddddr ,form))))
X
X(defun make-cdxr (n form)
X  (cond ((zerop n) form)
X	((< n 5) `(,(nth n '(identity cdr cddr cdddr cddddr)) ,form))
X	(t (make-cdxr (- n 4) `(cddddr ,form)))))
X
X(defmacro ignore (&rest vars)
X  #+Symbolics `(progn ,.(remove 'ignore vars))
X  #-Symbolics `(progn ,@vars))
X
X(defun true (&rest ignore) (ignore ignore) t)
X(defun false (&rest ignore) (ignore ignore) nil)
X
X;;; ONCE-ONLY does the same thing as it does in zetalisp.  I should have just
X;;; lifted it from there but I am honest.  Not only that but this one is
X;;; written in Common Lisp.  I feel a lot like bootstrapping, or maybe more
X;;; like rebuilding Rome.
X(defmacro once-only (vars &body body)
X  (let ((gensym-var (gensym))
X        (run-time-vars (gensym))
X        (run-time-vals (gensym))
X        (expand-time-val-forms ()))
X    (dolist (var vars)
X      (push `(if (or (symbolp ,var)
X                     (numberp ,var)
X                     (and (listp ,var)
X			  (member (car ,var) '(quote function))))
X                 ,var
X                 (let ((,gensym-var (gensym)))
X                   (push ,gensym-var ,run-time-vars)
X                   (push ,var ,run-time-vals)
X                   ,gensym-var))
X            expand-time-val-forms))    
X    `(let* (,run-time-vars
X            ,run-time-vals
X            (wrapped-body
X              ((lambda ,vars . ,body) . ,(reverse expand-time-val-forms))))
X       `((lambda ,(nreverse ,run-time-vars)  ,wrapped-body)
X         . ,(nreverse ,run-time-vals)))))
X
X(defun extract-declarations (body &optional environment)
X  (declare (values documentation declares body))
X  (let (documentation declares form temp)
X    (when (stringp (car body)) (setq documentation (pop body)))
X    (loop
X      (when (null body) (return))
X      (setq form (car body))
X      (cond ((and (listp form) (eq (car form) 'declare))
X	     (push (pop body) declares))
X;	    ((and (neq (setq temp (macroexpand form environment)) form)
X;		  (listp temp)
X;		  (eq (car temp) 'declare))
X;	     (pop body)
X;	     (push temp declares))
X	    (t (return))))
X    (values documentation declares body)))
X
X  ;;   
X;;;;;; FAST-NCONC Lists
X  ;;
X;;; These are based on Interlisp's TCONC function.  They are slighlty
X;;; generalized to take either the item to nconc onto the end of the list or
X;;; a cons to add to the end of a list. In addition there is a constructor to
X;;; make fast-nconc-lists and an accessor to get at a fast-nconc-list's real
X;;; list.
X(defmacro make-fast-nconc-list ()
X  `(let ((fast-nconc-list (cons () (list ()))))
X     (rplaca fast-nconc-list (cdr fast-nconc-list))
X     fast-nconc-list))
X
X(defmacro fast-nconc-list-real-list (fast-nconc-list)
X  `(cddr ,fast-nconc-list))
X
X(defmacro fast-nconc-cons (fast-nconc-list cons)
X  (once-only (fast-nconc-list)
X    `(progn (rplacd (car ,fast-nconc-list) ,cons)
X            (rplaca ,fast-nconc-list (cdar ,fast-nconc-list)))))
X
X(defmacro fast-nconc-item (fast-nconc-list item)
X  `(fast-nconc-cons ,fast-nconc-list (cons ,item nil)))
X
X#+Lucid
X(eval-when (compile load eval)
X  (eval `(defstruct ,(intern "FASLESCAPE" (find-package 'lucid)))))
X
X; rds 3/8 added -HP and +HP for make-keyword:
X#-HP
X(defun make-keyword (symbol)
X   (intern (symbol-name symbol) '#,(find-package 'keyword)))
X
X#+HP
X(defun make-keyword (symbol)
X   (intern (symbol-name symbol) (find-package 'keyword)))
X
X(defun string-append (&rest strings)
X  (setq strings (copy-list strings))		;The explorer can't even
X						;rplaca an &rest arg?
X  (do ((string-loc strings (cdr string-loc)))
X      ((null string-loc)
X       (apply #'concatenate 'string strings))
X    (rplaca string-loc (string (car string-loc)))))
X
X(defun symbol-append (sym1 sym2 &optional (package *package*))
X  (intern (string-append sym1 sym2) package))
X
X(defmacro check-member (place list &key (test #'eql) (pretty-name place))
X  (once-only (place list)
X    `(or (member ,place ,list :test ,test)
X         (error "The value of ~A, ~S is not one of ~S."
X                ',pretty-name ,place ,list))))
X
X
X
X;;; A simple version of destructuring-bind.
X
X;;; This does no more error checking than CAR and CDR themselves do.  Some
X;;; attempt is made to be smart about preserving intermediate values.  It
X;;; could be better, although the only remaining case should be easy for
X;;; the compiler to spot since it compiles to PUSH POP.
X;;;
X;;; Common Lisp BUG:
X;;;    Common Lisp should have destructuring-bind.
X;;;    
X(defmacro destructuring-bind (pattern form &body body)
X  (multiple-value-bind (ignore declares body)
X      (extract-declarations body)
X    (multiple-value-bind (setqs binds)
X	(destructure pattern form)
X      `(let ,binds
X	 ,@declares
X	 ,@setqs
X	 . ,body))))
X
X(defun destructure (pattern form)
X  (declare (values setqs binds))
X  (let ((*destructure-vars* ())
X	(setqs ()))
X    (declare (special *destructure-vars*))
X    (when (not (symbolp form))
X      (setq *destructure-vars* '(.destructure-form.)
X	    setqs (list `(setq .destructure-form. ,form)))
X      (setq form '.destructure-form.))
X    (values (nconc setqs (nreverse (destructure-internal pattern form)))
X	    (delete nil *destructure-vars*))))
X
X(defun destructure-internal (pattern form)
X  ;; When we are called, pattern must be a list.  Form should be a symbol
X  ;; which we are free to setq containing the value to be destructured.
X  ;; Optimizations are performed for the last element of pattern cases.
X  ;; we assume that the compiler is smart about gensyms which are bound
X  ;; but only for a short period of time.
X  (declare (special *destructure-vars*))
X  (let ((gensym (gensym))
X	(pending-pops 0)
X	(var nil)
X	(setqs ()))
X    (labels
X        ((make-pop (var form pop-into)
X	   (prog1 
X	     (cond ((zerop pending-pops)
X		    `(progn ,(and var `(setq ,var (car ,form)))
X			    ,(and pop-into `(setq ,pop-into (cdr ,form)))))
X		   ((null pop-into)
X		    (and var `(setq ,var ,(make-caxr pending-pops form))))
X		   (t
X		    `(progn (setq ,pop-into ,(make-cdxr pending-pops form))
X			    ,(and var `(setq ,var (pop ,pop-into))))))
X	     (setq pending-pops 0))))
X      (do ((pat pattern (cdr pat)))
X	  ((null pat) ())
X	(if (symbolp (setq var (car pat)))
X	    (progn
X	      (push var *destructure-vars*)
X	      (cond ((null (cdr pat))
X		     (push (make-pop var form ()) setqs))
X		    ((symbolp (cdr pat))
X		     (push (make-pop var form (cdr pat)) setqs)
X		     (push (cdr pat) *destructure-vars*)
X		     (return ()))
X		    ((memq var '(nil ignore)) (incf pending-pops))
X		    ((memq (cadr pat) '(nil ignore))
X		     (push (make-pop var form ()) setqs)
X		     (incf pending-pops 1))
X		    (t
X		     (push (make-pop var form form) setqs))))
X	    (progn
X	      (push `(let ((,gensym ()))
X		       ,(make-pop gensym form (if (symbolp (cdr pat)) (cdr pat) form))
X		       ,@(nreverse
X			   (destructure-internal (if (consp pat) (car pat) pat)
X						 gensym)))
X		    setqs)
X	      (when (symbolp (cdr pat))
X		(push (cdr pat) *destructure-vars*)
X		(return)))))
X      setqs)))
X
X;;; Iterate is a simple iteration macro.  If CommonLisp had a standard Loop
X;;; macro I wouldn't need this wretched crock.  But what the hell, it seems
X;;; to do most of what I need.  It looks like:
X;;;   (iterate (<control-clause-1> <control-clause-2> ...)
X;;;      . <body>)
X;;;
X;;;  a control clause can be one of:
X;;;   (<var> in <list-form>)  | (<var> in <list-form> by <function>)
X;;;   (<var> on <list-form>)  | (<var> on <list-form> by <function>)
X;;;   (<var> from <initial> to <final>)
X;;;   (<var> from <initial> below <final>)
X;;;   (<var> from <initial> to <final> by <function> | <increment>)
X;;;   (<var> from <initial> below <final> by <function> | <increment>)
X;;;   (<var> = <form>)   <form> is evaluated each time through
X;;;   (<var> = <initial> <subsequent>)
X;;;   
X;;;  inside <body> you are allowed to use:
X;;;    collect
X;;;    join
X;;;    sum
X
X(defvar *iterate-result-types* ())
X
X(defmacro define-iterate-result-type (name arglist &body body)
X  (let ((fn-name
X	  (if (and (null (cdr body)) (symbolp (car body)))
X	      (car body)
X	      (make-symbol (string-append (symbol-name name) " iterate result type")))))
X    `(progn
X       (let ((existing (assq ',name  *iterate-result-types*)))
X	 (if existing
X	     (rplacd existing ',fn-name)
X	     (push ',(cons name fn-name) *iterate-result-types*)))
X       ,(and (not (and (null (cdr body)) (symbolp (car body))))
X	     `(defun ,fn-name ,arglist . ,body)))))
X
X(defmacro iterate (controls &body body)
X  #+Xerox (setq body (copy-tree body))
X  (let (binds var-init-steps
X	pre-end-tests post-end-tests
X	pre-bodies post-bodies
X	(result-type ()))
X    (mapc #'(lambda (control)
X	      (let ((var (car control))
X		    (type (cadr control))
X		    (initial (caddr control))
X		    (args (cdddr control)))
X		(ecase type
X		  ((in on)
X		   (let* ((gensym (if (or (eq type 'in) (consp var)) (gensym) var))
X			  (step `(,(if args (cadr args) 'cdr) ,gensym)))
X		     (push `(,gensym ,initial ,step) var-init-steps)
X		     (push `(null ,gensym) pre-end-tests)
X		     (cond ((listp var)
X			    (multiple-value-bind (setqs dbinds)
X				(destructure var (if (eq type 'in) `(car ,gensym) gensym))
X			      (setq binds (nconc dbinds binds))
X			      (setq pre-bodies (nconc pre-bodies (nreverse setqs)))))
X			   ((eq type 'in)
X			    (push var binds)
X			    (push `(setq ,var (car ,gensym)) pre-bodies)))))
X		  (from
X		    (let ((gensym (gensym))
X			  (final
X			    (and (memq (car args) '(to below))
X				 (if (eq (car args) 'to)
X				     (cadr args)
X				     `(- ,(cadr args) 1))))
X			  (step
X			    (progn (setq args (member 'by args))
X				   (cond ((null args)
X					  `(1+ ,var))
X					 ((numberp (cadr args))
X					  `(+ ,var ,(cadr args)))
X					 (t (cadr args))))))
X		      (push `(,var ,initial ,step) var-init-steps)
X		      (and final (push `(,gensym ,final) binds))
X		      (and final (push `(> , var ,gensym) pre-end-tests))))
X		  (=
X		    (push `(,var ,initial ,(or (car args) initial))
X			  var-init-steps))
X		  )))
X	  controls)
X    (setq body
X	  (walk-form (cons 'progn body)
X		     :walk-function
X		     #'(lambda (form context &aux aux)
X			 (ignore context)
X			 (or (and (listp form)
X				  (setq aux (assq (car form) *iterate-result-types*))
X				  (setq result-type
X					(if (null result-type)
X					    (funcall (cdr aux)
X						     form nil 'create-result-type)
X					    (funcall (cdr aux)
X						     form result-type 'check-result-type)))
X				  (funcall (cdr aux) form result-type 'macroexpand))
X			     form))))
X    (let* ((initially (cons 'progn
X			    (dolist (tlf body)
X			      (when (and (consp tlf) (eq (car tlf) 'initially))
X				(return (prog1 (cdr tlf)
X					       (setf (car tlf) 'progn
X						     (cdr tlf) ())))))))
X	   (finally (cons 'progn
X			  (dolist (tlf body)
X			    (when (and (consp tlf) (eq (car tlf) 'finally))
X			      (return (prog1 (cdr tlf)
X					     (setf (car tlf) 'progn
X						   (cdr tlf) ()))))))))
X      `(let (,@binds . ,(caddr result-type))
X	 (iterate-macrolets
X	   (prog ,(mapcar #'(lambda (x) (list (car x) (cadr x)))
X			  var-init-steps)
X		 ,initially
X	      restart
X		 (and (or . ,(reverse pre-end-tests))
X		      (go .iterate_return.))
X		 (progn . ,(reverse pre-bodies))
X		 ,body
X		 (progn . ,(reverse post-bodies))
X		 (or ,@post-end-tests
X		     (progn ,@(mapcar #'(lambda (x)
X					  (and (cddr x)
X					       `(setq ,(car x)
X						      ,(caddr x))))
X				      var-init-steps)
X			    (go restart)))
X	      .iterate_return.
X		 ,finally
X		 (return ,(cadddr result-type))))))))
X
X(define-iterate-result-type collect (form result-type op)
X  iterate-collect-join)
X
X(define-iterate-result-type join (form result-type op)
X  iterate-collect-join)
X
X(defun iterate-collect-join (form result-type op)
X  (ecase op
X    (create-result-type
X      (let ((gensym (gensym)))
X	`(,(car form) ,gensym ((,gensym ())) (nreverse ,gensym))))
X    (check-result-type
X      (if (memq (car result-type) '(collect join))
X	  result-type
X	  (error "Using ~S inside an iterate in which you already used ~S."
X		 (car form) (car result-type))))
X    (macroexpand
X      (if (eq (car form) 'collect)
X	  `(push ,(cadr form) ,(cadr result-type))
X	  `(setq ,(cadr result-type)
X		 (append (reverse ,(cadr form)) ,(cadr result-type)))))))
X
X(define-iterate-result-type sum (form result-type op)
X  (ecase op
X    (create-result-type
X      (let ((gensym (gensym)))
X	`(,(car form) ,gensym ((,gensym 0)) ,gensym)))
X    (check-result-type
X      (eq (car result-type) 'sum))
X    (macroexpand
X      `(incf ,(cadr result-type) ,(cadr form)))))
X
X(defmacro iterate-macrolets (&body body)
X  `(macrolet
X     ((until (test)
X        `(when ,test (go .iterate_return.)))
X      (while (test)
X	`(until (not ,test)))
X      (initially (&body body)
X	(error
X	  "It is an error for FINALLY to appear other than at top-level~%~
X	   inside an iterate."))
X      (finally (&body ignore)
X	(error
X	  "It is an error for INITIALLY to appear other than at top-level~%~
X           inside an iterate."))
X      )
X     . ,body))
X  
X;;;
X;;; Two macros useful for parsing defstructs.
X;;; The first parses slot-description (or lambda-list) style keyword-value
X;;; pairs.  The second, more complicated one, parses defstruct option style
X;;; keyword-value pairs.
X;;;
X(defmacro keyword-bind (keywords form &body body)
X  `(apply (function (lambda (&key . ,keywords) . ,body)) ,form))
X
X;;;
X;;;   (keyword-parse (<keyword-spec-1> <keyword-spec-2> ..)
X;;;                  form
X;;;      . body)
X;;;
X;;; Where form is a form which will be evaluated and should return the list
X;;; of keywords and values which keyword-parse will parse.  Body will be
X;;; evaluated with the variables specified by the keyword-specs bound.
X;;; Keyword specs look like:
X;;;        <var>
X;;;        (<var> <default>)
X;;;        (<var> <default> <suppliedp var>)
X;;;        (<var> <default> <suppliedp var> <option-1> <val-1> ...)
X;;;
X;;;    The options can be:
X;;;       :allowed     ---  :required   :multiple
X;;;       :return-cdr  ---  t           nil
X;;;       
X(defmacro keyword-parse (keywords form &body body)
X  ;; This makes an effort to resemble keyword-bind in that the vars are bound
X  ;; one at a time so that a default value form can look at the value of a
X  ;; previous argument. This is probably more hair than its worth, but what
X  ;; the hell, programming is fun.
X  (let* ((lambda-list ())
X         (supplied-p-gensyms ())
X         (value-forms ())
X         (entry-var (gensym)))
X    (dolist (kw keywords)
X      (unless (listp kw) (setq kw (list kw)))      
X      (destructuring-bind (var default supplied-p-var . options) kw
X        (keyword-bind (presence (allowed ':required) return-cdr) options
X          (push var lambda-list)
X          (when supplied-p-var
X            (push supplied-p-var lambda-list)
X            (push (gensym) supplied-p-gensyms))
X          (push `(let ((,entry-var (keyword-parse-assq ',(make-keyword var)
X						       ,form
X						       ',allowed)))
X                   (if (null ,entry-var)
X                       ,default
X                       ;; Insert appropriate error-checking based on the
X                       ;; allowed argument.
X                       (progn
X                       ,(when (null allowed)
X                          `(unless (nlistp (car ,entry-var))
X                             (error "The ~S keyword was supplied with an ~
X                                    argument, it is not allowed to have one."
X                                    ',(make-keyword var))))
X                       ,(when (eq allowed ':required)
X                          `(unless (listp (car ,entry-var))
X                             (error
X			       "The ~S keyword was supplied without an ~
X                                argument~%when present, this keyword must ~
X                                have an argument."
X                               ',(make-keyword var))))
X                       (cond ((listp (car ,entry-var))
X                              ,(and supplied-p-var
X                                    `(setq ,(car supplied-p-gensyms) 't))
X                              ,(if return-cdr
X				   (if (eq allowed ':multiple)
X				       `(mapcar #'cdr ,entry-var)
X				       `(cdar ,entry-var))
X				   (if (eq allowed ':multiple)
X				       `(mapcar #'cadr ,entry-var)
X				       `(cadar ,entry-var))))
X                             (t
X                              ,(and supplied-p-var
X                                    `(setq ,(car supplied-p-gensyms)
X					   ':presence))
X                              ,presence)))))
X                value-forms)
X          (when supplied-p-var
X            (push (car supplied-p-gensyms) value-forms)))))
X    `(let ,supplied-p-gensyms
X       ((lambda ,(reverse lambda-list) . ,body) . ,(reverse value-forms)))))
X
X
X(defun keyword-parse-assq (symbol list allowed)
X  (do ((result nil result)
X       (tail list (cdr tail)))
X      ((null tail) (nreverse result))
X    (if (eq (if (symbolp (car tail)) (car tail) (caar tail)) symbol)
X	(if (neq allowed ':multiple)
X	    (return tail)
X	    (push (car tail) result)))))
X
X  ;;   
X;;;;;; printing-random-thing
X  ;;
X;;; Similar to printing-random-object in the lisp machine but much simpler
X;;; and machine independent.
X(defmacro printing-random-thing ((thing stream) &body body)
X  (once-only (stream)
X  `(let ((*print-level* (and (numberp *print-level*) (- *print-level* 1))))
X     (progn (princ "#<" ,stream)
X            ,@body
X	    (princ " " ,stream)
X	    (printing-random-thing-internal ,thing ,stream)
X	    (princ ">" ,stream)))))
X
X(defun printing-random-thing-internal (thing stream)
X  (ignore thing stream)
X  nil)
X
X  ;;   
X;;;;;; 
X  ;;
X
X(defun capitalize-words (string)
X  (let ((string (copy-seq (string string))))
X    (declare (string string))
X    (do* ((flag t flag)
X	  (length (length string) length)
X	  (char nil char)
X	  (i 0 (+ i 1)))
X	 ((= i length) string)
X      (setq char (elt string i))
X      (cond ((both-case-p char)
X	     (if flag
X		 (and (setq flag (lower-case-p char))
X		      (setf (elt string i) (char-upcase char)))
X		 (and (not flag) (setf (elt string i) (char-downcase char))))
X	     (setq flag nil))
X	    ((char-equal char #\-)
X	     (setq flag t))
X	    (t (setq flag nil))))))
X
X  ;;
X;;;;;; CLASS-NAMED  naming classes.
X  ;;
X;;;
X;;; (CLASS-NAMED <name>) returns the class named <name>.  setf can be used
X;;; with class-named to set the class named <name>.  These are "extrinsic"
X;;; names.  Neither class-named nor setf of class-named do anything with the
X;;; name slot of the class, they only lookup and change the association from
X;;; name to class.
X;;; 
X
X(defvar *class-name-hash-table* (make-hash-table :test #'eq))
X
X(defun class-named (name &optional no-error-p)
X  (or (gethash name *class-name-hash-table*)
X      (if no-error-p () (error "No class named: ~S." name))))
X
X(defsetf class-named (name &optional ignore-damnit) (class)
X  `(setf (gethash ,name *class-name-hash-table*) ,class))
X
X
X(defvar *discriminator-name-hash-table* (make-hash-table :test #'eq
X							 :size 1000))
X
X(defun discriminator-named (name)		        ;This a function for
X  (gethash name *discriminator-name-hash-table*))	;the benefit of
X						        ;compile-time-define?
X
X(defun set-discriminator-named (name new-value)
X  (setf (gethash name *discriminator-name-hash-table*) new-value))
X
X(defsetf discriminator-named set-discriminator-named)
X
X;;;
X;;; To define a macro which is only applicable in the body of a defmethod,
X;;; use define-method-body-macro.  This macro takes two arguments the name
X;;; of the macro that should be defined in the body of the method and the
X;;; function which should be called to expand calls to that macro.
X;;; 
X;;; Expander-function will be called with 3 arguments:
X;;; 
X;;;   the entire macro form (gotten with &whole)
X;;;   the macroexpand-time-information
X;;;   the environment
X;;;   
X
X(defvar *method-body-macros* ())
X
X(defmacro define-method-body-macro (name arglist &key global method)
X  (when (eq global :error)
X    (setq global
X	  `(progn (warn "~S used outside the body of a method." ',name)
X		  '(error "~S used outside the body of a method." ',name))))
X  (or method
X      (error "Have to provide a value for the method-body definition of~%~
X              a macro defined with define-method-body-macro."))
X  #+KCL (when (memq '&environment arglist)
X	  ;; In KCL, move &environment to the beginning of the
X	  ;; arglist since they require that it be there.
X	  (unless (eq (car arglist) '&environment)
X	    (do ((loc arglist (cdr loc)))
X		((eq (cadr loc) '&environment)
X		 (setq arglist (list* (cadr loc) (caddr loc) arglist))
X		 (setf (cdr loc) (cdddr loc))))))
X  (let ((body-expander-function (gensym))
X	(parameters (remove lambda-list-keywords arglist
X			    :test #'(lambda (x y) (member y x)))))
X    `(eval-when (compile load eval)
X       ,(and global `(defmacro ,name ,arglist ,global))
X       (defun ,body-expander-function
X	      (macroexpand-time-environment ,@parameters)
X	 ,method)
X	 
X       (let ((entry (or (assq ',name *method-body-macros*)
X			(progn (push (list ',name) *method-body-macros*)
X			       (car *method-body-macros*)))))
X	 (setf (cdr entry) (list ',arglist
X				 ',parameters
X				 ',body-expander-function))))))
X
X  ;;   
X;;;;;; Special variable definitions.
X  ;;
X;;; Gets set to its right value once early-defmeths are fixed.
X;;; 
X(defvar *error-when-defining-method-on-existing-function* 'bootstrapping
X  "If this variable is non-null (the default) defmethod signals an error when
X   a method is defined on an existing lisp-function without first calling
X   make-specializable on that function.")
X
END_OF_FILE
if test 25561 -ne `wc -c <'macros.l'`; then
    echo shar: \"'macros.l'\" unpacked with wrong size!
fi
# end of 'macros.l'
fi
echo shar: End of archive 7 \(of 13\).
cp /dev/null ark7isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 13 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 

Rich $alz			"Anger is an energy"
Cronus Project, BBN Labs	rsalz@bbn.com
Moderator, comp.sources.unix	sources@uunet.uco-dmk