[comp.sources.unix] v10i086: Common Objects, Common Loops, Common Lisp, Part12/13

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

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

#! /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 12 (of 13)."
# Contents:  methods.l
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'methods.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'methods.l'\"
else
echo shar: Extracting \"'methods.l'\" \(42046 characters\)
sed "s/^X//" >'methods.l' <<'END_OF_FILE'
X;;;-*-Mode:LISP; Package: PCL; 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
X(in-package 'pcl)
X
X  ;;   
X;;;;;; Methods
X  ;;   
X
X(ndefstruct (essential-method
X	      (:class class)
X	      (:conc-name method-))
X  (discriminator nil)
X  (arglist ())
X  (type-specifiers ())
X  (function nil))
X
X(ndefstruct (combinable-method-mixin (:class class)))
X
X(ndefstruct (basic-method
X	      (:class class)
X	      (:include (essential-method))
X	      (:constructor make-method-1)
X	      (:conc-name method-))
X  (function nil)
X  (discriminator nil)
X  (type-specifiers ())
X  (arglist ())
X  (options () :allocation :dynamic))
X
X(ndefstruct (method (:class class)
X		    (:include (combinable-method-mixin
X			       basic-method))))
X
X
X(ndefstruct (essential-discriminator
X	      (:class class)
X	      (:conc-name discriminator-))
X  (name nil)
X  (methods ())
X  (discriminating-function ())
X  (classical-method-table nil :allocation :dynamic)
X  (cache ()))
X
X(ndefstruct (method-combination-mixin (:class class)
X				      (:conc-name nil))
X  (method-combination-type :daemon)
X  (method-combination-parameters ())
X  (methods-combine-p ())
X  )
X
X(ndefstruct (basic-discriminator
X	      (:class class)
X	      (:include (essential-discriminator))
X	      (:constructor make-discriminator-1)
X	      (:conc-name discriminator-))
X
X  (dispatch-order :default)  
X  (inactive-methods () :allocation :dynamic))
X
X(ndefstruct (discriminator (:class class)
X			   (:include (method-combination-mixin
X				      basic-discriminator)))
X  )
X
X;;;
X;;; This is really just for bootstrapping, of course this isn't all
X;;; worked out yet.  But this SHOULD really just be for bootstrapping.
X;;; 
X(defmeth method-causes-combination-p ((method basic-method))
X  (ignore method)
X  ())
X
X  ;;   
X;;;;;; 
X  ;;   
X
X
X(defun real-expand-defmeth (name&options arglist body)
X  (unless (listp name&options) (setq name&options (list name&options)))
X  (keyword-parse ((discriminator-class 'discriminator)
X                  (method-class 'method))
X                 (cdr name&options)
X    (dolist (x '(:discriminator-class :method-class))
X      (delete x name&options :test #'(lambda (x y)
X				       (and (listp y) (eq (car y) x)))))
X    (let ((discriminator-class-object (class-named discriminator-class t))
X          (method-class-object (class-named method-class t)))
X      (or discriminator-class-object		;
X          (error
X	    "The :DISCRIMINATOR-CLASS option to defmeth was used to specify~
X             that the class~%of the discriminator should be ~S;~%~
X             but there is no class named ~S."
X	    discriminator-class
X	    discriminator-class))
X      (or method-class-object
X          (error "The :METHOD-CLASS option to defmeth was used to specify~%~
X                  that the class of the method should be ~S;~%~
X                  but there is no class named ~S."
X                 method-class
X                 method-class))
X      (expand-defmeth-internal (class-prototype discriminator-class-object)
X			       (class-prototype method-class-object)
X			       name&options
X			       arglist
X			       body))))
X
X(defvar *method-being-defined*)
X
X(defmeth expand-defmeth-internal ((proto-discriminator basic-discriminator)
X				  (proto-method basic-method)
X				  name&options arglist body)
X  (keyword-parse ((setf () setf-specified-p))
X                 (cdr name&options)
X    (let* ((discriminator-class-name (class-name
X				       (class-of proto-discriminator)))
X           (method-class-name (class-name (class-of proto-method)))
X           (name (car name&options))
X           (merged-arglist (cons (car arglist) (append setf (cdr arglist))))
X           (merged-args (arglist-without-type-specifiers proto-discriminator
X                                                         proto-method
X                                                         merged-arglist))
X           (merged-type-specifiers
X	     (defmethod-argument-specializers arglist))
X           discriminator-name
X           method-name
X	   (defmethod-uid (gensym))
X	   (load-method-1 ())
X	   (documentation ())
X	   (declarations ()))
X      (if setf-specified-p
X	  (setq discriminator-name (make-setf-discriminator-name name)
X		method-name (make-setf-method-name name
X						   (arglist-type-specifiers
X						     proto-discriminator
X						     proto-method
X						     setf)
X						   merged-type-specifiers))
X	  (setq discriminator-name name
X		method-name (make-method-name name
X					      merged-type-specifiers)))
X      (multiple-value-setq (documentation declarations body)
X	(extract-declarations body))
X      (setq load-method-1 `(,discriminator-class-name
X			    ,method-class-name
X			    ,discriminator-name
X			    ,merged-type-specifiers
X			    ,merged-args
X			    ,(cdr name&options)))
X      ;;
X      ;; There are 4 cases:
X      ;;   - evaluated
X      ;;   - compiled to core
X      ;;   - compiled to file
X      ;;   - loading the compiled file
X      ;;
X      ;; When loading a method which has a run-super in it, there is no way
X      ;; to know which of two events will happen first:
X      ;;   1. the load-time-eval form in the run super will be
X      ;;      evaluated first, or
X      ;;   2. the function to install the loaded method (defmethod-uid)
X      ;;      will be evaluated first.
X      ;; consequently, both the special function (defmethod-uid) and the
X      ;; expansion of run-super must check to see if the other has already
X      ;; run and set the value of defmethod-uid to the method involved.
X      ;; This is what causes the boundp checks of defmethod-uid each time
X      ;; before it is set.
X      ;; 
X      `(progn
X	 
X	 (eval-when (eval load)
X	   
X	   (defun ,defmethod-uid ()
X	     (declare (special ,defmethod-uid))
X	     (unless (boundp ',defmethod-uid)
X	       (setq ,defmethod-uid (apply #'load-method-1
X					   ',load-method-1)))
X	     ,@(and *real-methods-exist-p*
X		    `((record-definition
X			',discriminator-name 'method
X			',merged-type-specifiers ',(cdr name&options))
X		      (setf (symbol-function ',method-name)
X			    #'(lambda ,merged-args
X				,@documentation
X				,@declarations
X				(declare (method-function-name ,method-name))
X				,(wrap-method-body
X				   proto-discriminator
X				   (apply 'compile-method-1 load-method-1)
X				   discriminator-name
X				   defmethod-uid
X				   load-method-1
X				   body)
X				))))
X	     
X	     (setf (method-function ,defmethod-uid)
X		   (symbol-function ',method-name))
X	     
X	     (add-method (discriminator-named ',discriminator-name)
X			 ,defmethod-uid
X			 ()))
X	   
X	   (,defmethod-uid))
X	 
X	 (eval-when (compile load eval)
X	   
X	   ,@(and setf-specified-p
X		  `((record-definition
X		      ',name 'defsetf ',discriminator-name 'defmeth)
X		    (defsetf ,name
X			     ,(arglist-without-type-specifiers
X				proto-discriminator proto-method arglist)
X			     ,(arglist-without-type-specifiers
X				proto-discriminator proto-method setf)
X		      (list ',discriminator-name ,@(arglist-args
X						     proto-discriminator
X						     proto-method
X						     merged-args)))))
X	   
X	   ',discriminator-name)))))
X
X(defmethod wrap-method-body ((mex-generic-function discriminator)
X			     (mex-method method)
X			     generic-function-name
X			     method-uid
X			     load-method-1-args
X			     body)
X  (let ((macroexpand-time-information (list mex-generic-function
X					    mex-method
X					    generic-function-name
X					    method-uid
X					    load-method-1-args)))
X    `(macrolet ,(iterate (((name arglist params fn) in *method-body-macros*))
X		  (collect `(,name ,arglist
X			       (funcall (function ,fn)
X					',macroexpand-time-information
X					,@params))))
X       (block ,generic-function-name
X	 . ,body))))
X
X(defun macroexpand-time-generic-function (mti) (nth 0 mti))
X
X(defun macroexpand-time-method (mti) (nth 1 mti))
X
X(defun macroexpand-time-generic-function-name (mti) (nth 2 mti))
X
X(defun macroexpand-time-method-uid (mti) (nth 3 mti))
X
X(defun macroexpand-time-load-method-1-args (mti) (nth 4 mti))
X
X
X(defun load-method-1 (discriminator-class-name
X		       method-class-name
X		       discriminator-name
X		       method-type-specifiers
X		      method-arglist
X		      options)
X  (let* ((discriminator
X	   (ensure-selector-specializable
X	     (class-prototype (class-named discriminator-class-name))
X	     discriminator-name
X	     method-arglist))
X	 (method
X	   (or (find-method discriminator method-type-specifiers options t)
X	       (make method-class-name))))
X    (setf (method-arglist method) method-arglist)
X    (setf (method-type-specifiers method)
X	  (parse-type-specifiers
X	    discriminator method method-type-specifiers))
X    (setf (method-options method) options)
X    method))
X
X(defun compile-method-1 (discriminator-class-name
X			 method-class-name
X			 discriminator-name
X			 method-type-specifiers
X			 method-arglist
X			 options)
X  (ignore discriminator-name)
X  (let ((method (make method-class-name)))
X    (setf (method-arglist method) method-arglist)
X    (setf (method-type-specifiers method)
X          (parse-type-specifiers
X	    (class-prototype (class-named discriminator-class-name))
X	    method
X	    method-type-specifiers))
X    (setf (method-options method) options)
X    method))
X
X
X
X(defmeth add-named-method ((proto-discriminator essential-discriminator)
X			   (proto-method essential-method)
X			   discriminator-name
X			   arglist
X			   type-specs
X			   extra
X			   function)
X  ;; What about changing the class of the discriminator if there is
X  ;; one.  Whose job is that anyways.  Do we need something kind of
X  ;; like class-for-redefinition?
X  (let* ((discriminator
X	   ;; Modulo bootstrapping hair, this is just:
X	   ;;   (or (discriminator-named ..)
X	   ;;       (make-specializable))
X	   (ensure-selector-specializable proto-discriminator
X					  discriminator-name
X					  arglist))
X	 (existing (find-method discriminator type-specs extra t))
X	 (method (or existing
X		     (make (class-of proto-method)))))
X    (when existing (change-class method (class-of proto-method)))
X    (setf (method-arglist method) arglist)
X    (setf (method-function method) function)
X    (setf (method-type-specifiers method) type-specs)
X    (add-method discriminator method extra)))
X
X(defmeth add-method ((discriminator essential-discriminator)
X		     (method essential-method)
X		     extra)
X  (ignore extra)
X  (let ((type-specs (method-type-specifiers method))
X       ;(options (method-options method))
X       ;(methods (discriminator-methods discriminator))
X	)
X    (setf (method-discriminator method) discriminator)
X;    ;; Put the new method where it belongs, either:
X;    ;;  - The same (EQ) method object is already on discriminator-methods
X;    ;;    of the discriminator so we don't need to do anything to put the
X;    ;;    new methods where it belongs.
X;    ;;  - There is an method on discriminator-methods which is equal to
X;    ;;    the new method (according to METHOD-EQUAL).  In this case, we
X;    ;;    replace the existing method with the new one.
X;    ;;  - We just add the new method to discriminator-methods by pushing
X;    ;;    it onto that list.
X;    (unless (memq method methods)
X;      (do* ((tail (discriminator-methods discriminator) (cdr tail))
X;	    (existing-method (car tail) (car tail)))
X;	   ((cond ((null existing-method)		 
X;		   (push method (discriminator-methods discriminator)))
X;		  ((method-equal existing-method type-specs options)
X;		   (remove-method discriminator existing-method)
X;		   (return (add-method discriminator method))))
X;	    
X;	    (when (method-causes-combination-p method)	         ;NOT part of
X;	      (pushnew method (methods-combine-p discriminator)));standard
X;						                 ;protocol.
X;	    (dolist (argument-specifier type-specs)
X;	      (add-method-on-argument-specifier discriminator
X;						method
X;						argument-specifier)))
X;	()))
X    (pushnew method (discriminator-methods discriminator))
X    (dolist (argument-specifier type-specs)
X      (add-method-on-argument-specifier discriminator
X					method
X					argument-specifier)))
X    (discriminator-changed discriminator method t)
X    (update-pretty-arglist discriminator method)	;NOT part of
X						        ;standard protocol.
X    ())
X
X
X(defmeth remove-named-method (discriminator-name
X			      argument-specifiers
X			      &optional extra)
X  (let ((discriminator ())
X	(method ()))
X    (cond ((null (setq discriminator (discriminator-named
X				       discriminator-name)))
X	   (error "There is no discriminator named ~S." discriminator-name))
X	  ((null (setq method (find-method discriminator
X					   argument-specifiers 
X					   extra
X					   t)))
X	   (error "There is no method for the discriminator ~S~%~
X                   which matches the argument-specifiers ~S."
X		  discriminator
X		  argument-specifiers))
X	  (t
X	   (remove-method discriminator method)))))
X
X(defmeth remove-method ((discriminator basic-discriminator) method)
X  (setf (method-discriminator method) nil)
X  (setf (discriminator-methods discriminator)
X	(delq method (discriminator-methods discriminator)))
X  (dolist (type-spec (method-type-specifiers method))
X    (remove-method-on-argument-specifier discriminator method type-spec))
X  (discriminator-changed discriminator method nil)
X  discriminator)
X
X
X
X(defmeth add-method-on-argument-specifier
X	 ((discriminator essential-discriminator)
X	  (method essential-method)
X	  argument-specifier)
X  (ignore method)
X  (when (classp argument-specifier)
X    (pushnew method
X	     (class-direct-methods argument-specifier))
X    ;; This is a bug.  This needs to be split up into a method on
X    ;; essential class and a method on class or something.
X    (when (methods-combine-p discriminator)
X      (pushnew discriminator
X	       (class-discriminators-which-combine-methods
X		 argument-specifier)))))
X
X(defmeth remove-method-on-argument-specifier
X	 ((discriminator essential-discriminator)
X	  (method essential-method)
X	  argument-specifier)
X  (ignore method)
X  (when (classp argument-specifier)
X    (setf (class-direct-methods argument-specifier)
X	  (delq method
X		(class-direct-methods argument-specifier)))
X    (when (methods-combine-p discriminator)
X      (setf (class-discriminators-which-combine-methods
X	      argument-specifier)
X	    (delq discriminator
X		  (class-discriminators-which-combine-methods
X		    argument-specifier))))))
X
X
X(defun make-specializable (function-name &rest options)
X  (when options (setq options (list* ':allow-other-keys t options)))
X  (keyword-bind ((arglist nil arglist-specified-p)
X		 (discriminator-class 'discriminator)
X		 (dispatch nil dispatch-p))
X		options
X    (cond ((not (null arglist-specified-p)))
X	  ((fboundp 'function-arglist)
X	   ;; function-arglist exists, get the arglist from it.
X	   ;; Note: the funcall of 'function-arglist prevents
X	   ;;       compiler warnings at least in some lisps.
X	   (setq arglist (funcall 'function-arglist function-name)))
X	  ((fboundp function-name)
X	   (error
X	     "The :arglist argument to make-specializable was not supplied~%~
X              and there is no version of FUNCTION-ARGLIST defined for this~%~
X              port of Portable CommonLoops.~%~
X              You must either define a version of FUNCTION-ARGLIST (which~%~
X              should be easy), and send it off to the Portable CommonLoops~%~
X              people or you should call make-specializable again with the~%~
X              function's arglist as its second argument.")))
X    (setq dispatch
X	  (if dispatch-p
X	      (iterate ((disp in dispatch))
X		(unless (memq disp arglist)
X		  (error "There is a symbol in the :dispatch argument (~S)~%~
X                          which isn't in the arglist."))
X		(collect (position disp arglist)))
X	      :default))
X    (let ((discriminator-class-object
X	    (if (classp discriminator-class)
X		discriminator-class
X		(class-named discriminator-class t)))
X	  (discriminator nil))
X      (if (null discriminator-class-object)
X	  (error
X	    "The :DISCRIMINATOR-CLASS argument to make-specializable is ~S~%~
X             but there is no class by that name."
X	    discriminator-class)
X	  (setq discriminator             
X		(apply #'make discriminator-class-object
X		       :name function-name
X		       :dispatch-order dispatch
X		       options)))
X;     (setf (function-pretty-arglist function-name) arglist)
X      (if arglist-specified-p
X	  (put-slot-always discriminator 'pretty-arglist arglist)
X	  (remove-dynamic-slot discriminator 'pretty-arglist))
X      (setf (discriminator-named function-name) discriminator)
X      (when (fboundp function-name)
X	(add-named-method (class-prototype (class-named 'discriminator))
X			  (class-prototype (class-named 'method))
X			  function-name
X			  arglist
X			  ()
X			  ()
X			  (symbol-function function-name)))
X      discriminator)))
X
X
X
X
X
X(defun update-pretty-arglist (discriminator method)
X  (setf (function-pretty-arglist
X	  (or (discriminator-name discriminator)
X	      (discriminator-discriminating-function discriminator)))
X	(or (get-slot-using-class (class-of discriminator) discriminator
X				  'pretty-arglist t ())
X	    (method-arglist method))))
X
X(defmeth discriminator-pretty-arglist ((discriminator basic-discriminator))
X  (or (get-slot-using-class (class-of discriminator) discriminator
X			    'pretty-arglist t ())
X      (let ((method (or (discriminator-default-method discriminator)
X			(car (discriminator-methods discriminator)))))
X	(and method (method-arglist method)))))
X
X(defmeth ensure-selector-specializable ((proto-discriminator
X					   essential-discriminator)
X					 selector arglist)
X  (let ((discriminator (discriminator-named selector)))
X    (cond ((not (null discriminator)) discriminator)
X          ((or (not (fboundp selector))
X               (eq *error-when-defining-method-on-existing-function*
X		   'bootstrapping))
X           (setf (discriminator-named selector)
X                 (make (class-of proto-discriminator) :name selector)))
X          ((null *error-when-defining-method-on-existing-function*)
X           (make-specializable selector
X			       :arglist arglist
X			       :discriminator-class (class-of
X						      proto-discriminator))
X           (discriminator-named selector))
X          (t
X           (error "Attempt to add a method to the lisp function ~S without~%~
X                   first calling make-specializable.  Before attempting to~
X                   define a method on ~S~% you should evaluate the form:~%~
X                   (~S '~S)"
X                  selector selector 'make-specializable selector)))))
X
X(defmeth find-method (discriminator type-specifiers options &optional parse)
X  (iterate ((method in (discriminator-methods discriminator)))
X    (when (method-equal method
X			(if parse
X			    (parse-type-specifiers discriminator
X						   method
X						   type-specifiers)
X			    type-specifiers)
X			options)
X      (return method))))
X
X(defmeth method-equal ((method basic-method) argument-specifiers options)
X  (and (equal options (method-options method))
X       (equal argument-specifiers (method-type-specifiers method))))
X
X
X(defmeth discriminator-default-method ((discriminator essential-discriminator))
X  (find-method discriminator () ()))
X
X(defmeth install-discriminating-function ((discriminator
X					    essential-discriminator)
X					  where
X					  function
X					  &optional inhibit-compile-p)
X  (ignore discriminator)
X  (check-type where symbol "a symbol other than NIL")
X  (check-type function function "a funcallable object")
X  
X  (when (and (listp function)
X	     (eq (car function) 'lambda)
X	     (null inhibit-compile-p))
X    (setq function (compile nil function)))
X
X  (if where
X      (setf (symbol-function where) function)
X      (setf (discriminator-discriminating-function discriminator) function)))
X
X
X  ;;   
X;;;;;; Discriminator-Based caching.
X  ;;
X;;; Methods are cached in a discriminator-based cache.  The cache is an N-key
X;;; cache based on the number of specialized arguments the discriminator has.
X;;; As yet the size of the cache does not change statically or dynamically.
X;;; Because of this I allow myself the freedom of computing the mask at
X;;; compile time and not even storing it in the discriminator.
X
X(defvar *default-discriminator-cache-size* 8)
X
X(defun make-discriminator-cache (&optional
X				  (size *default-discriminator-cache-size*))
X  (make-memory-block size))
X
X(defun make-discriminator-cache-mask (discriminator-cache
X				      no-of-specialized-args)
X  (make-memory-block-mask (memory-block-size discriminator-cache)
X                          (+ no-of-specialized-args 1)))
X
X(defmeth flush-discriminator-caches ((discriminator essential-discriminator))
X  (let ((cache (discriminator-cache discriminator)))
X    (when cache (clear-memory-block (discriminator-cache discriminator) 0))))
X
X(defmeth initialize-discriminator-cache ((self essential-discriminator)
X                                            no-of-specialized-args)
X  (ignore no-of-specialized-args)
X  (unless (discriminator-cache self)
X    (setf (discriminator-cache self) (make-discriminator-cache))))
X
X(defmacro discriminator-cache-offset (mask &rest classes)
X  `(logand ,mask
X           ,@(iterate ((class in classes))
X	       (collect `(object-cache-no ,class ,mask)))))
X
X(defmacro discriminator-cache-entry (cache offset offset-from-offset)
X  `(memory-block-ref ,cache (+ ,offset ,offset-from-offset)))
X
X(defmacro cache-method (cache mask method-function &rest classes)
X  `(let* ((.offset. (discriminator-cache-offset ,mask ,@classes)))
X     ;; Once again, we have to endure a little brain damage because we can't
X     ;; count on having without-interrupts.  I suppose the speed loss isn't
X     ;; too significant since this is only when we get a cache miss.
X     (setf (discriminator-cache-entry ,cache .offset. 0) nil)
X     ,@(iterate ((class in (cdr classes)) (key-no from 1))
X         (collect `(setf (discriminator-cache-entry ,cache .offset. ,key-no)
X			 ,class)))
X     (prog1
X       (setf (discriminator-cache-entry ,cache .offset. ,(length classes))
X	     ,method-function)
X       (setf (discriminator-cache-entry ,cache .offset. 0) ,(car classes)))))
X
X(defmacro cached-method (var cache mask &rest classes)
X  `(let ((.offset. (discriminator-cache-offset ,mask . ,classes)))
X     (and ,@(iterate ((class in classes) (key-no from 0))
X              (collect
X                `(eq (discriminator-cache-entry ,cache .offset. ,key-no)
X		     ,class)))
X          (setq ,var (discriminator-cache-entry ,cache
X						.offset.
X						,(length classes)))
X          t)))
X
X(defmeth make-caching-discriminating-function (discriminator lookup-function
X							      cache
X							      mask)
X  (multiple-value-bind (required restp specialized-positions)
X      (compute-discriminating-function-arglist-info discriminator)
X    (funcall (get-templated-function-constructor
X	       'caching-discriminating-function
X	       required
X	       restp
X	       specialized-positions
X	       lookup-function)
X             discriminator cache mask)))
X
X(defun make-checking-discriminating-function (discriminator method-function
X                                                            type-specs
X							    default-function)
X  (multiple-value-bind (required restp)
X      (compute-discriminating-function-arglist-info discriminator)
X    (let ((check-positions
X	    (iterate ((type-spec in type-specs)
X		      (pos from 0))
X	      (collect (and (neq type-spec 't) pos)))))
X      (apply (get-templated-function-constructor
X	       'checking-discriminating-function
X	       required
X	       restp
X	       (if default-function t nil)
X	       check-positions)
X             discriminator method-function default-function type-specs))))
X
X
X  ;;   
X;;;;;; 
X  ;;   
X
X(defvar *always-remake-discriminating-function* nil)
X
X(defmeth make-discriminating-function ((discriminator
X					 essential-discriminator))
X  (let ((default (discriminator-default-method discriminator))
X        (methods (discriminator-methods discriminator)))
X    (cond ((null methods)
X	   (make-no-methods-discriminating-function discriminator))
X	  ((and default (null (cdr methods)))
X           (make-default-method-only-discriminating-function discriminator))
X          ((or (and default (null (cddr methods)))
X	       (and (null default) (null (cdr methods))))
X           (make-single-method-only-discriminating-function discriminator))
X          ((every #'(lambda (m)
X                      (classical-type-specifiers-p
X			(method-type-specifiers m)))
X                  methods)
X           (make-classical-methods-only-discriminating-function
X	     discriminator))
X          (t
X           (make-multi-method-discriminating-function discriminator)))))
X
X(defmeth make-no-methods-discriminating-function (discriminator)
X  (instaar *always-remake-discriminating-function* nil)
X (discriminator-name discriminator)
X    #'(lambda (&rest ignore)
X	(error "There are no methods on the discriminator ~S,~%~
X                so it is an error to call it."
X	       discriminator))))
X
X(defmeth make-default-method-only-discriminating-function
X	 ((self essential-discriminator))
X  (install-discriminating-function
X    self
X    (discriminator-name self)
X    (method-function (discriminator-default-method self))))
X
X(defmeth make-single-method-only-discriminating-function
X	  ((self essential-discriminator))
X  (let* ((methods (discriminator-methods self))
X	 (default (discriminator-default-method self))
X	 (method (if (eq (car methods) default)
X		     (cadr methods)
X		     (car methods)))
X         (method-type-specifiers (method-type-specifiers method))
X         (method-function (method-function method)))
X    (install-discriminating-function
X      self
X      (discriminator-name self)
X      (make-checking-discriminating-function
X	self
X	method-function
X	method-type-specifiers
X	(and default (method-function default))))))
X
X(defmeth make-classical-methods-only-discriminating-function
X	  ((self essential-discriminator))
X  (initialize-discriminator-cache self 1)
X  (let ((default-method (discriminator-default-method self))
X	(methods (discriminator-methods self)))
X    (setf (discriminator-classical-method-table self)
X	  (cons (and default-method (method-function default-method))
X		(iterate ((method in methods))
X		  (unless (eq method default-method)
X		    (collect (cons (car (method-type-specifiers method))
X				   (method-function method))))))))
X  (let* ((cache (discriminator-cache self))
X	 (mask (make-discriminator-cache-mask cache 1)))
X    (install-discriminating-function
X      self
X      (discriminator-name self)
X      (make-caching-discriminating-function
X	self 'lookup-classical-method cache mask))))
X
X(defun lookup-classical-method (discriminator class)
X  ;; There really should be some sort of more sophisticated protocol going
X  ;; on here.  Compare type-specifiers and all that.
X  (let* ((classical-method-table
X	   (get-slot--class discriminator 'classical-method-table)))
X    (or (iterate ((super in (get-slot--class class 'class-precedence-list)))
X          (let ((hit (assq super (cdr classical-method-table))))
X            (when hit (return (cdr hit)))))
X	(car classical-method-table))))
X
X(defmeth make-multi-method-discriminating-function
X	  ((self essential-discriminator))
X  (multiple-value-bind (required restp specialized)
X      (compute-discriminating-function-arglist-info self)
X    (ignore required restp)
X    (initialize-discriminator-cache self (length specialized))
X    (let* ((cache (discriminator-cache self))
X	   (mask (make-discriminator-cache-mask cache (length specialized))))
X      (install-discriminating-function
X	self
X	(discriminator-name self)
X	(make-caching-discriminating-function
X	  self 'lookup-multi-method cache mask)))))
X
X(defvar *lookup-multi-method-internal*
X	(make-array (min 256. call-arguments-limit)))
X
X(defun lookup-multi-method-internal (discriminator classes)
X  (let* ((methods (discriminator-methods discriminator))
X	 (cpls *lookup-multi-method-internal*)
X	 (order (get-slot--class discriminator 'dispatch-order))
X         (most-specific-method nil)
X         (most-specific-type-specs ())
X	 (type-specs ()))
X    ;; Put all the class-precedence-lists in a place where we can save
X    ;; them as we look through all the methods.
X    (without-interrupts
X      (iterate ((class in classes)
X		(i from 0))
X	(setf (svref cpls i) (get-slot--class class 'class-precedence-list)))
X      (dolist (method methods)
X	(setq type-specs (get-slot--class method 'type-specifiers))
X	(when (iterate ((type-spec in  type-specs)
X			(i from 0))
X		(or (eq type-spec 't)
X		    (memq type-spec (svref cpls i))
X		    (return nil))
X		(finally (return t)))
X	  (if (null most-specific-method)
X	      (setq most-specific-method method
X		    most-specific-type-specs type-specs)
X	      (case (compare-type-specifier-lists
X		      most-specific-type-specs type-specs nil
X		      () classes order)
X		(2 (setq most-specific-method method
X			 most-specific-type-specs type-specs))
X		(1))))))
X    (or most-specific-method
X	(discriminator-default-method discriminator))))
X
X(defun lookup-multi-method (discriminator &rest classes)
X  (declare (inline lookup-multi-method-internal))
X  (let ((method (lookup-multi-method-internal discriminator classes)))
X    (and method (method-function method))))
X
X(defun lookup-method (discriminator &rest classes)
X  (declare (inline lookup-multi-method-internal))
X  (lookup-multi-method-internal discriminator classes))
X
X  ;;   
X;;;;;; Code for parsing arglists (in the usual case).
X  ;;   (when discriminator is class DISCRIMINATOR and method is class METHOD)
X;;;
X;;; arglist-type-specifiers
X;;; Given an arglist this returns its type-specifiers.  Trailing T's (both
X;;; implicit and explicit) are dropped.  The type specifiers are returned as
X;;; they are found in the arglist, they are not parsed into internal
X;;; type-specs.
X;;;
X(defmeth arglist-type-specifiers ((proto-disc basic-discriminator)
X				  (proto-meth basic-method)
X				  arglist)
X  (let ((arg (car arglist)))
X    (and arglist
X         (not (memq arg '(&optional &rest &key &aux)))  ;Don't allow any
X                                                        ;type-specifiers
X	                                                ;after one of these.
X         (let ((tail (arglist-type-specifiers proto-disc
X					      proto-meth
X					      (cdr arglist)))
X               (type-spec (and (listp arg) (cadr arg))))
X           (or (and tail (cons (or type-spec 't) tail))
X               (and type-spec (cons type-spec ())))))))
X
X;;; arglist-without-type-specifiers
X;;; Given an arglist remove the type specifiers.
X;;; 
X(defmeth arglist-without-type-specifiers ((proto-disc basic-discriminator)
X					  (proto-meth basic-method)
X					  arglist)
X  (let ((arg (car arglist)))
X    (and arglist
X         (if (memq arg '(&optional &rest &key &aux))    ;don't allow any
X                                                        ;type-specifiers
X                                                        ;after one of these.
X             arglist
X             (cons (if (listp arg) (car arg) arg)
X                   (arglist-without-type-specifiers proto-disc
X						    proto-meth
X						    (cdr arglist)))))))
X
X(defmeth arglist-args ((discriminator-class basic-discriminator)
X		       (method-class basic-method)
X		       arglist)
X  (and arglist
X       (cond ((eq (car arglist) '&aux) ())
X             ((memq (car arglist) '(&optional &rest &key))
X              (arglist-args discriminator-class method-class (cdr arglist)))
X             (t
X              ;; This plays on the fact that no type specifiers are allowed
X	      ;; on arguments that can have default values.
X              (cons (if (listp (car arglist)) (caar arglist) (car arglist))
X                    (arglist-args discriminator-class
X				  method-class
X				  (cdr arglist)))))))
X
X(defmeth parse-type-specifiers ((proto-discriminator basic-discriminator)
X				(proto-method basic-method)
X				type-specifiers)
X  (iterate ((type-specifier in type-specifiers))
X    (collect (parse-type-specifier proto-discriminator
X				   proto-method
X				   type-specifier))))
X
X(defmeth parse-type-specifier ((proto-discriminator basic-discriminator)
X                                (proto-method basic-method)
X                                type-specifier)
X  (ignore proto-discriminator proto-method)
X  (cond ((eq type-specifier 't) 't)
X        ((symbolp type-specifier)
X         (or (class-named type-specifier nil)
X             (error
X	       "~S used as a type-specifier, but is not the name of a class."
X	       type-specifier)))
X        ((classp type-specifier) type-specifier)
X        (t (error "~S is not a legal type-specifier." type-specifier))))
X
X(defmeth unparse-type-specifiers ((method essential-method))
X  (iterate ((parsed-type-spec in (method-type-specifiers method)))
X    (collect (unparse-type-specifier method parsed-type-spec))))
X
X(defmeth unparse-type-specifier ((method essential-method) type-spec)
X  (ignore method)
X  (if (classp type-spec)
X      (class-name type-spec)
X      type-spec))
X
X(defun classical-type-specifiers-p (typespecs)
X  (or (null typespecs)
X      (and (classp (car typespecs))
X           (null (cdr typespecs)))))
X
X;;;
X;;; Compute various information about a discriminator's arglist by looking at
X;;; the argument lists of the methods.  The hair for trying not to use &rest
X;;; arguments lives here.
X;;;  The values returned are:
X;;;    number-of-required-arguments
X;;;       the number of required arguments to this discrimator's
X;;;       discriminating function
X;;;    &rest-argument-p
X;;;       whether or not this discriminator's discriminating
X;;;       function takes an &rest argument.
X;;;    specialized-argument-positions
X;;;       a list of the positions of the arguments this discriminator
X;;;       specializes (e.g. for a classical discrimator this is the
X;;;       list: (1)).
X;;;
X;;; As usual, it is legitimate to specialize the -internal function that is
X;;; why I put it there, since I certainly could have written this more
X;;; efficiently if I didn't want to provide that extensibility.
X;;; 
X(defmeth compute-discriminating-function-arglist-info
X	 ((discriminator essential-discriminator)
X	  &optional (methods () methods-p))
X  (declare (values number-of-required-arguments
X                   &rest-argument-p
X                   specialized-argument-postions))
X  (unless methods-p
X    (setq methods (discriminator-methods discriminator)))
X  (let ((number-required nil)
X        (restp nil)
X        (specialized-positions ()))
X    (iterate ((method in methods))
X      (multiple-value-setq (number-required restp specialized-positions)
X        (compute-discriminating-function-arglist-info-internal
X	  discriminator method number-required restp specialized-positions)))
X    (values number-required restp (sort specialized-positions #'<))))
X
X(defmeth compute-discriminating-function-arglist-info-internal
X	 ((discriminator essential-discriminator)
X	  (method essential-method)
X	  number-of-requireds restp specialized-argument-positions)
X  (ignore discriminator)
X  (let ((requireds 0))
X    ;; Go through this methods arguments seeing how many are required,
X    ;; and whether there is an &rest argument.
X    (iterate ((arg in (method-arglist method)))
X      (cond ((eq arg '&aux) (return))
X            ((memq arg '(&optional &rest &key))
X             (return (setq restp t)))
X	    ((memq arg lambda-list-keywords))
X            (t (incf requireds))))
X    ;; Now go through this method's type specifiers to see which
X    ;; argument positions are type specified.  Treat T specially
X    ;; in the usual sort of way.  For efficiency don't bother to
X    ;; keep specialized-argument-positions sorted, rather depend
X    ;; on our caller to do that.
X    (iterate ((type-spec in (method-type-specifiers method))
X              (pos from 0))
X      (unless (eq type-spec 't)
X	(pushnew pos specialized-argument-positions)))
X    ;; Finally merge the values for this method into the values
X    ;; for the exisiting methods and return them.  Note that if
X    ;; num-of-requireds is NIL it means this is the first method
X    ;; and we depend on that.
X    (values (min (or number-of-requireds requireds) requireds)
X            (or restp
X		(and number-of-requireds (/= number-of-requireds requireds)))
X            specialized-argument-positions)))
X
X(defun make-discriminating-function-arglist (number-required-arguments restp)
X  (iterate ((i from 0 below number-required-arguments))
X    (collect (intern (format nil "Discriminating Function Arg ~D" i)))
X    (finally (when restp
X               (collect '&rest)
X               (collect (intern "Discriminating Function &rest Arg"))))))
X
X(defmeth compare-methods (discriminator method-1 method-2)
X  (ignore discriminator)
X  (let ((compare ()))
X    (iterate ((ts-1 in (method-type-specifiers method-1))
X	      (ts-2 in (method-type-specifiers method-2)))
X      (cond ((eq ts-1 ts-2) (setq compare '=))
X	    ((eq ts-1 't)   (setq compare method-2))
X	    ((eq ts-2 't)   (setq compare method-1))	    
X	    ((memq ts-1 (class-class-precedence-list ts-2))
X	     (setq compare method-2))
X	    ((memq ts-2 (class-class-precedence-list ts-1))
X	     (setq compare method-1))
X	    (t (return nil)))
X      (finally (return compare)))))
X
X  ;;   
X;;;;;; Comparing type-specifiers, statically or wrt an object.
X  ;;
X;;; compare-type-specifier-lists compares two lists of type specifiers
X;;; compare-type-specifiers compare two type specifiers
X;;; If static-p it t the comparison is done statically, otherwise it is
X;;; done with respect to object(s).  The value returned is:
X;;;    1    if type-spec-1 is more specific
X;;;    2    if type-spec-2 is more specific
X;;;    =    if they are equal
X;;;    NIL  if they cannot be disambiguated
X;;;
X(defun compare-type-specifier-lists (type-spec-list-1
X				     type-spec-list-2
X				     staticp
X				     args
X				     classes
X				     order)
X  (when (or type-spec-list-1 type-spec-list-2)
X    (ecase (compare-type-specifiers (or (car type-spec-list-1) t)
X                                    (or (car type-spec-list-2) t)
X                                    staticp
X                                    (car args)
X                                    (car classes))
X      (1 '1)
X      (2 '2)
X      (= (if (eq order :default)
X	     (compare-type-specifier-lists (cdr type-spec-list-1)
X					   (cdr type-spec-list-2)
X					   staticp
X					   (cdr args)
X					   (cdr classes)
X					   order)
X	     (compare-type-specifier-lists (nth (car order) type-spec-list-1)
X					   (nth (car order) type-spec-list-2)
X					   staticp
X					   (cdr args)
X					   (cdr classes)
X					   (cdr order))))
X	    
X      (nil
X        (unless staticp
X          (error "The type specifiers ~S and ~S can not be disambiguated~
X                  with respect to the argument: ~S"
X                 (or (car type-spec-list-1) t)
X                 (or (car type-spec-list-2) t)
X                 (car args)
X                 (car classes)))))))
X
X(defun compare-type-specifiers (type-spec-1 type-spec-2 staticp arg class)
X  (cond ((equal type-spec-1 type-spec-2) '=)
X        ((eq type-spec-2 t) '1)
X        ((eq type-spec-1 t) '2)
X        ((and (classp type-spec-1) (classp type-spec-2))
X;        (if staticp
X;            (if (common-subs type-spec-1 type-spec-2)
X;                nil
X;                (let ((supers (common-supers type-spec-1 type-spec-2)))
X;                  (cond ((cdr supers) nil)
X;                        ((eq (car supers) type-spec-1) '2)
X;                        ((eq (car supers) type-spec-2) '1)
X;                        (t 'disjoint))))
X             (iterate ((super in (class-class-precedence-list (or class (class-of arg)))))
X               (cond ((eq super type-spec-1)
X                      (return '1))
X                     ((eq super type-spec-2)
X                      (return '2)))))
X;)
X        (t
X         (compare-complex-type-specifiers type-spec-1 type-spec-2 staticp arg class))))
X
X(defun compare-complex-type-specifiers (type-spec-1 type-spec-2 static-p arg class)
X  (ignore type-spec-1 type-spec-2 static-p arg class)
X  (error "Complex type specifiers are not yet supported."))
X
X(defmeth no-matching-method (discriminator)
X  (let ((class-of-discriminator (class-of discriminator)))
X    (if (eq (class-of class-of-discriminator) (class-named 'class))
X        ;; The meta-class of the discriminator is class, we can get at
X        ;; it's name slot without doing any method lookup.
X        (let ((name (get-slot--class discriminator 'name)))
X          (if (and name (symbolp name))
X              (error "No matching method for: ~S." name)
X              (error "No matching method for the anonymous discriminator: ~S."
X                     discriminator)))
X        (error "No matching method for the discriminator: ~S." discriminator))))
X  ;;   
X;;;;;; Optimizing GET-SLOT
X  ;;   
X
X(defmeth method-argument-class ((method basic-method) argument)
X  (let* ((arglist (method-arglist method))
X         (position (position argument arglist)))
X    (and position (nth position (method-type-specifiers method)))))
X
X
X(defmeth optimize-get-slot ((class basic-class)
X			    form)
X  (declare (ignore class))
X  (cons 'get-slot--class (cdr form)))
X
X(defmeth optimize-setf-of-get-slot ((class basic-class)
X				    form)
X  (declare (ignore class))
X  (cons 'put-slot--class (cdr form)))
X
END_OF_FILE
if test 42046 -ne `wc -c <'methods.l'`; then
    echo shar: \"'methods.l'\" unpacked with wrong size!
fi
# end of 'methods.l'
fi
echo shar: End of archive 12 \(of 13\).
cp /dev/null ark12isdone
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.uubodys