Ticket #66: run-d-m-c-20100811a.diff

File run-d-m-c-20100811a.diff, 21.5 KB (added by Mark Evenson, 14 years ago)

long form of DEFINE-METHOD-COMBINATION snapshot

  • src/org/armedbear/lisp/clos.lisp

    diff -r 8ce380ea40f4 src/org/armedbear/lisp/clos.lisp
    a b  
    4949;;; protocol as described in "The Art of The Metaobject Protocol",
    5050;;; MIT Press, 1991.
    5151
     52(proclaim '(optimize (debug 3)))
     53
    5254(in-package #:mop)
    5355
    5456(export '(class-precedence-list class-slots))
     
    740742                 ,(canonicalize-direct-slots direct-slots)
    741743                 ,@(canonicalize-defclass-options options)))
    742744
    743 (eval-when (:compile-toplevel :load-toplevel :execute)
    744   (defstruct method-combination
    745     name
    746     operator
    747     identity-with-one-argument
    748     documentation)
    749 
    750   (defun expand-short-defcombin (whole)
    751     (let* ((name (cadr whole))
    752            (documentation
    753             (getf (cddr whole) :documentation ""))
    754            (identity-with-one-arg
    755             (getf (cddr whole) :identity-with-one-argument nil))
    756            (operator
    757             (getf (cddr whole) :operator name)))
    758       `(progn
    759          (setf (get ',name 'method-combination-object)
    760                (make-method-combination :name ',name
    761                                         :operator ',operator
    762                                         :identity-with-one-argument ',identity-with-one-arg
    763                                         :documentation ',documentation))
    764          ',name)))
    765 
    766   (defun expand-long-defcombin (whole)
    767     (declare (ignore whole))
    768     (error "The long form of DEFINE-METHOD-COMBINATION is not implemented.")))
    769 
    770 (defmacro define-method-combination (&whole form &rest args)
    771   (declare (ignore args))
     745(defstruct method-combination
     746  name
     747  documentation)
     748
     749(defstruct (short-method-combination
     750             (:include method-combination))
     751  operator
     752  identity-with-one-argument)
     753
     754(defstruct (long-method-combination
     755             (:include method-combination))
     756  lambda-list
     757  method-group-specs
     758  args-lambda-list
     759  generic-function-symbol
     760  function
     761  arguments
     762  declarations
     763  forms)
     764
     765(defun expand-long-defcombin (name args)
     766  (destructuring-bind (lambda-list method-groups &rest body) args
     767    `(apply #'define-long-form-method-combination
     768            ',name
     769            ',lambda-list
     770            (list ,@(mapcar #'canonicalize-method-group-spec method-groups))
     771            ',body)))
     772
     773(defun expand-short-defcombin (whole)
     774  (let* ((name (cadr whole))
     775         (documentation
     776          (getf (cddr whole) :documentation ""))
     777         (identity-with-one-arg
     778          (getf (cddr whole) :identity-with-one-argument nil))
     779         (operator
     780          (getf (cddr whole) :operator name)))
     781    `(progn
     782       (setf (get ',name 'method-combination-object)
     783             (make-short-method-combination
     784              :name ',name
     785              :operator ',operator
     786              :identity-with-one-argument ',identity-with-one-arg
     787              :documentation ',documentation))
     788       ',name)))
     789
     790(defmacro define-method-combination (&whole form name &rest args)
    772791  (if (and (cddr form)
    773792           (listp (caddr form)))
    774       (expand-long-defcombin form)
     793      (expand-long-defcombin name args)
    775794      (expand-short-defcombin form)))
    776795
    777796(define-method-combination +      :identity-with-one-argument t)
     
    784803(define-method-combination or     :identity-with-one-argument t)
    785804(define-method-combination progn  :identity-with-one-argument t)
    786805
     806;;;
     807;;; long form of define-method-combination (from Sacla and XCL)
     808;;;
     809(defun define-method-combination-type (name &rest initargs)
     810    (setf (get name 'method-combination-object)
     811          (apply 'make-long-method-combination initargs)))
     812
     813(defun method-group-p (selecter qualifiers)
     814  ;; selecter::= qualifier-pattern | predicate
     815  (etypecase selecter
     816    (list (or (equal selecter qualifiers)
     817              (let ((last (last selecter)))
     818                (when (eq '* (cdr last))
     819                  (let* ((prefix `(,@(butlast selecter) ,(car last)))
     820                         (pos (mismatch prefix qualifiers)))
     821                    (or (null pos) (= pos (length prefix))))))))
     822    ((eql *) t)
     823    (symbol (funcall (symbol-function selecter) qualifiers))))
     824
     825(defun check-variable-name (name)
     826  (flet ((valid-variable-name-p (name)
     827                                (and (symbolp name) (not (constantp name)))))
     828    (assert (valid-variable-name-p name))))
     829
     830(defun canonicalize-method-group-spec (spec)
     831  ;; spec ::= (name {qualifier-pattern+ | predicate} [[long-form-option]])
     832  ;; long-form-option::= :description description | :order order |
     833  ;;                     :required required-p
     834  ;; a canonicalized-spec is a simple plist.
     835  (let* ((rest spec)
     836         (name (prog2 (check-variable-name (car rest))
     837                 (car rest)
     838                 (setq rest (cdr rest))))
     839         (option-names '(:description :order :required))
     840         (selecters (let ((end (or (position-if #'(lambda (it)
     841                                                   (member it option-names))
     842                                                rest)
     843                                   (length rest))))
     844                      (prog1 (subseq rest 0 end)
     845                        (setq rest (subseq rest end)))))
     846         (description (getf rest :description ""))
     847         (order (getf rest :order :most-specific-first))
     848         (required-p (getf rest :required)))
     849    `(list :name ',name
     850           :predicate (lambda (qualifiers)
     851                        (loop for item in ',selecters
     852                          thereis (method-group-p item qualifiers)))
     853           :description ',description
     854           :order ,order
     855           :required ',required-p)))
     856
     857(defun extract-required-part (lambda-list)
     858  (flet ((skip (key lambda-list)
     859               (if (eq (first lambda-list) key)
     860                   (cddr lambda-list)
     861                   lambda-list)))
     862    (ldiff (skip '&environment (skip '&whole lambda-list))
     863           (member-if #'(lambda (it) (member it lambda-list-keywords))
     864                      lambda-list))))
     865
     866(defun extract-specified-part (key lambda-list)
     867  (case key
     868    ((&eval &whole)
     869     (list (second (member key lambda-list))))
     870    (t
     871     (let ((here (cdr (member key lambda-list))))
     872       (ldiff here
     873              (member-if #'(lambda (it) (member it lambda-list-keywords))
     874                         here))))))
     875
     876(defun extract-optional-part (lambda-list)
     877  (extract-specified-part '&optional lambda-list))
     878
     879(defun parse-define-method-combination-arguments-lambda-list (lambda-list)
     880  ;; Define-method-combination Arguments Lambda Lists
     881  ;; http://www.lispworks.com/reference/HyperSpec/Body/03_dj.htm
     882  (let ((required (extract-required-part lambda-list))
     883        (whole    (extract-specified-part '&whole    lambda-list))
     884        (optional (extract-specified-part '&optional lambda-list))
     885        (rest     (extract-specified-part '&rest     lambda-list))
     886        (keys     (extract-specified-part '&key      lambda-list))
     887        (aux      (extract-specified-part '&aux      lambda-list)))
     888    (values (first whole)
     889            required
     890            (mapcar #'(lambda (spec)
     891                       (if (consp spec)
     892                           `(,(first spec) ,(second spec) ,@(cddr spec))
     893                           `(,spec nil)))
     894                    optional)
     895            (first rest)
     896            (mapcar #'(lambda (spec)
     897                       (let ((key (if (consp spec) (car spec) spec))
     898                             (rest (when (consp spec) (rest spec))))
     899                         `(,(if (consp key) key `(,(make-keyword key) ,key))
     900                           ,(car rest)
     901                           ,@(cdr rest))))
     902                    keys)
     903            (mapcar #'(lambda (spec)
     904                       (if (consp spec)
     905                           `(,(first spec) ,(second spec))
     906                           `(,spec nil)))
     907                    aux))))
     908
     909(defmacro getk (plist key init-form)
     910  "Similar to getf except eval and return INIT-FORM if KEY has no value in PLIST."
     911  (let ((not-exist (gensym))
     912        (value (gensym)))
     913    `(let ((,value (getf ,plist ,key ,not-exist)))
     914       (if (eq ,not-exist ,value) ,init-form ,value))))
     915
     916(defconstant +gf-args-var+ (make-symbol "GF-ARGS-VAR"))
     917
     918(defmacro with-args-lambda-list (args-lambda-list generic-function-symbol
     919                                                  &body forms)
     920  (let ((gf-lambda-list (gensym))
     921        (nrequired (gensym))
     922        (noptional (gensym))
     923        (rest-args (gensym)))
     924    (multiple-value-bind (whole required optional rest keys aux)
     925        (parse-define-method-combination-arguments-lambda-list args-lambda-list)
     926      `(let* ((,gf-lambda-list (slot-value ,generic-function-symbol 'lambda-list))
     927              (,nrequired (length (extract-required-part ,gf-lambda-list)))
     928              (,noptional (length (extract-optional-part ,gf-lambda-list)))
     929              (,rest-args (subseq ,+gf-args-var+ (+ ,nrequired ,noptional)))
     930              ,@(when whole `((,whole ,+gf-args-var+)))
     931              ,@(loop for var in required and i upfrom 0
     932                  collect `(,var (when (< ,i ,nrequired)
     933                                   (nth ,i ,+gf-args-var+))))
     934              ,@(loop for (var init-form) in optional and i upfrom 0
     935                  collect
     936                  `(,var (if (< ,i ,noptional)
     937                             (nth (+ ,nrequired ,i) ,+gf-args-var+)
     938                             ,init-form)))
     939              ,@(when rest `((,rest ,rest-args)))
     940              ,@(loop for ((key var) init-form) in keys and i upfrom 0
     941                  collect `(,var (getk ,rest-args ',key ,init-form)))
     942              ,@(loop for (var init-form) in aux and i upfrom 0
     943                  collect `(,var ,init-form)))
     944         ,@forms))))
     945
     946(defmacro with-method-groups (method-group-specs methods-form &body forms)
     947  (flet ((grouping-form (spec methods-var)
     948                        (let ((predicate (coerce-to-function (getf spec :predicate)))
     949                              (group (gensym))
     950                              (leftovers (gensym))
     951                              (method (gensym)))
     952                          `(let ((,group '())
     953                                 (,leftovers '()))
     954                             (dolist (,method ,methods-var)
     955                               (if (funcall ,predicate (method-qualifiers ,method))
     956                                   (push ,method ,group)
     957                                   (push ,method ,leftovers)))
     958                             (ecase ,(getf spec :order)
     959                               (:most-specific-last )
     960                               (:most-specific-first (setq ,group (nreverse ,group))))
     961                             ,@(when (getf spec :required)
     962                                 `((when (null ,group)
     963                                     (error "Method group ~S must not be empty."
     964                                            ',(getf spec :name)))))
     965                             (setq ,methods-var (nreverse ,leftovers))
     966                             ,group))))
     967    (let ((rest (gensym))
     968          (method (gensym)))
     969      `(let* ((,rest ,methods-form)
     970              ,@(mapcar #'(lambda (spec)
     971                           `(,(getf spec :name) ,(grouping-form spec rest)))
     972                        method-group-specs))
     973         (dolist (,method ,rest)
     974           (invalid-method-error ,method
     975                                 "Method ~S with qualifiers ~S does not belong to any method group."
     976                                 ,method (method-qualifiers ,method)))
     977         ,@forms))))
     978
     979(defun method-combination-type-lambda
     980  (&key name lambda-list args-lambda-list generic-function-symbol
     981        method-group-specs declarations forms &allow-other-keys)
     982  (let ((methods (gensym)))
     983    `(lambda (,generic-function-symbol ,methods ,@lambda-list)
     984       ,@declarations
     985       (let ((*message-prefix* ,(format nil "METHOD COMBINATION TYPE ~S: " name)))
     986         (with-method-groups ,method-group-specs
     987           ,methods
     988           ,@(if (null args-lambda-list)
     989                 forms
     990                 `((with-args-lambda-list ,args-lambda-list
     991                     ,generic-function-symbol
     992                     ,@forms))))))))
     993
     994(defun declarationp (expr)
     995  (and (consp expr) (eq (car expr) 'DECLARE)))
     996
     997(defun long-form-method-combination-args (args)
     998  ;; define-method-combination name lambda-list (method-group-specifier*) args
     999  ;; args ::= [(:arguments . args-lambda-list)]
     1000  ;;          [(:generic-function generic-function-symbol)]
     1001  ;;          [[declaration* | documentation]] form*
     1002  (let ((rest args))
     1003    (labels ((nextp (key) (and (consp (car rest)) (eq key (caar rest))))
     1004             (args-lambda-list ()
     1005               (when (nextp :arguments)
     1006                 (prog1 (cdr (car rest)) (setq rest (cdr rest)))))
     1007             (generic-function-symbol ()
     1008                (if (nextp :generic-function)
     1009                    (prog1 (second (car rest)) (setq rest (cdr rest)))
     1010                    (gensym)))
     1011             (declaration* ()
     1012               (let ((end (position-if-not #'declarationp rest)))
     1013                 (when end
     1014                   (prog1 (subseq rest 0 end) (setq rest (nthcdr end rest))))))
     1015             (documentation? ()
     1016               (when (stringp (car rest))
     1017                 (prog1 (car rest) (setq rest (cdr rest)))))
     1018             (form* () rest))
     1019      (let ((declarations '()))
     1020        `(:args-lambda-list ,(args-lambda-list)
     1021                            :generic-function-symbol ,(generic-function-symbol)
     1022                            :documentation ,(prog2 (setq declarations (declaration*))
     1023                                              (documentation?))
     1024                            :declarations (,@declarations ,@(declaration*))
     1025                            :forms ,(form*))))))
     1026
     1027(defun define-long-form-method-combination (name lambda-list method-group-specs
     1028                                                 &rest args)
     1029  (let* ((initargs `(:name ,name
     1030                     :lambda-list ,lambda-list
     1031                     :method-group-specs ,method-group-specs
     1032                     ,@(long-form-method-combination-args args)))
     1033         (lambda-expression (apply #'method-combination-type-lambda initargs)))
     1034    (apply #'define-method-combination-type name
     1035           `(,@initargs
     1036;;              :function ,(compile nil lambda-expression)
     1037             :function ,(coerce-to-function lambda-expression)))
     1038    name))
     1039
    7871040(defstruct eql-specializer
    7881041  object)
    7891042
     
    15801833         (primaries '())
    15811834         (arounds '())
    15821835         around
    1583          emf-form)
    1584     (dolist (m methods)
    1585       (let ((qualifiers (method-qualifiers m)))
    1586         (cond ((null qualifiers)
    1587                (if (eq mc-name 'standard)
    1588                    (push m primaries)
    1589                    (error "Method combination type mismatch.")))
    1590               ((cdr qualifiers)
    1591                (error "Invalid method qualifiers."))
    1592               ((eq (car qualifiers) :around)
    1593                (push m arounds))
    1594               ((eq (car qualifiers) mc-name)
    1595                (push m primaries))
    1596               ((memq (car qualifiers) '(:before :after)))
    1597               (t
    1598                (error "Invalid method qualifiers.")))))
     1836         emf-form
     1837         (long-method-combination-p
     1838          (typep (get mc-name 'method-combination-object) 'long-method-combination)))
     1839    (unless long-method-combination-p
     1840      (dolist (m methods)
     1841        (let ((qualifiers (method-qualifiers m)))
     1842          (cond ((null qualifiers)
     1843                 (if (eq mc-name 'standard)
     1844                     (push m primaries)
     1845                     (error "Method combination type mismatch.")))
     1846                ((cdr qualifiers)
     1847                 (error "Invalid method qualifiers."))
     1848                ((eq (car qualifiers) :around)
     1849                 (push m arounds))
     1850                ((eq (car qualifiers) mc-name)
     1851                 (push m primaries))
     1852                ((memq (car qualifiers) '(:before :after)))
     1853                (t
     1854                 (error "Invalid method qualifiers."))))))
    15991855    (unless (eq order :most-specific-last)
    16001856      (setf primaries (nreverse primaries)))
    16011857    (setf arounds (nreverse arounds))
    16021858    (setf around (car arounds))
    1603     (when (null primaries)
     1859    (when (and (null primaries) (not long-method-combination-p))
    16041860      (error "No primary methods for the generic function ~S." gf))
    16051861    (cond
    16061862      (around
     
    16111867                   #'compute-effective-method-function)
    16121868               gf (remove around methods))))
    16131869         (setf emf-form
    1614 ;;;           `(lambda (args)
    1615 ;;;          (funcall ,(%method-function around) args ,next-emfun))
    1616                (generate-emf-lambda (%method-function around) next-emfun)
    1617                )))
     1870               (generate-emf-lambda (%method-function around) next-emfun))))
    16181871      ((eq mc-name 'standard)
    16191872       (let* ((next-emfun (compute-primary-emfun (cdr primaries)))
    16201873              (befores (remove-if-not #'before-method-p methods))
     
    16241877               (cond
    16251878                 ((and (null befores) (null reverse-afters))
    16261879                  (let ((fast-function (%method-fast-function (car primaries))))
    1627 
    16281880                    (if fast-function
    16291881                        (ecase (length (gf-required-args gf))
    16301882                          (1
     
    16351887                           #'(lambda (args)
    16361888                               (declare (optimize speed))
    16371889                               (funcall fast-function (car args) (cadr args)))))
    1638                         ;;                               `(lambda (args)
    1639                         ;;                                  (declare (optimize speed))
    1640                         ;;                                  (funcall ,(%method-function (car primaries)) args ,next-emfun))
    16411890                        (generate-emf-lambda (%method-function (car primaries))
    16421891                                             next-emfun))))
    16431892                 (t
    16441893                  (let ((method-function (%method-function (car primaries))))
    1645 
    16461894                    #'(lambda (args)
    16471895                        (declare (optimize speed))
    16481896                        (dolist (before befores)
     
    16511899                            (funcall method-function args next-emfun)
    16521900                          (dolist (after reverse-afters)
    16531901                            (funcall (%method-function after) args nil))))))))))
    1654           (t
    1655            (let ((mc-obj (get mc-name 'method-combination-object)))
    1656              (unless mc-obj
    1657                (error "Unsupported method combination type ~A." mc-name))
    1658              (let* ((operator (method-combination-operator mc-obj))
    1659                     (ioa (method-combination-identity-with-one-argument mc-obj)))
    1660                (setf emf-form
    1661                      (if (and (null (cdr primaries))
    1662                               (not (null ioa)))
    1663 ;;                          `(lambda (args)
    1664 ;;                             (funcall ,(%method-function (car primaries)) args nil))
    1665                          (generate-emf-lambda (%method-function (car primaries)) nil)
    1666                          `(lambda (args)
    1667                             (,operator ,@(mapcar
    1668                                           (lambda (primary)
    1669                                             `(funcall ,(%method-function primary) args nil))
    1670                                           primaries)))))))))
    1671     (or (ignore-errors (autocompile emf-form))
     1902      (long-method-combination-p
     1903       (let* ((mc-obj (get mc-name 'method-combination-object))
     1904              (function (long-method-combination-function mc-obj))
     1905              (arguments (rest (slot-value gf 'method-combination))))
     1906         (assert (typep mc-obj 'long-method-combination))
     1907         (assert function)
     1908         (setf emf-form
     1909               (let ((result (if arguments
     1910                                 (apply function gf methods arguments)
     1911                                 (funcall function gf methods))))
     1912                 `(lambda (args)
     1913                    (let ((gf-args-var args))
     1914                      (macrolet ((call-method (method &optional next-method-list)
     1915                                   `(funcall ,(%method-function method) args nil)))
     1916                        ,result)))))))
     1917      (t
     1918       (let ((mc-obj (get mc-name 'method-combination-object)))
     1919         (unless (typep mc-obj 'short-method-combination)
     1920           (error "Unsupported method combination type ~A."
     1921                  mc-name))
     1922         (let* ((operator (short-method-combination-operator mc-obj))
     1923                (ioa (short-method-combination-identity-with-one-argument mc-obj)))
     1924           (setf emf-form
     1925                 (if (and (null (cdr primaries))
     1926                          (not (null ioa)))
     1927                     (generate-emf-lambda (%method-function (car primaries)) nil)
     1928                     `(lambda (args)
     1929                        (,operator ,@(mapcar
     1930                                      (lambda (primary)
     1931                                        `(funcall ,(%method-function primary) args nil))
     1932                                      primaries)))))))))
     1933    (assert (not (null emf-form)))
     1934    (or #+nil (ignore-errors (autocompile emf-form))
    16721935        (coerce-to-function emf-form))))
    16731936
    16741937(defun generate-emf-lambda (method-function next-emfun)
     
    24552718  (std-method-more-specific-p method1 method2 required-classes
    24562719                              (generic-function-argument-precedence-order gf)))
    24572720
     2721;;; XXX AMOP has COMPUTE-EFFECTIVE-METHOD
    24582722(defgeneric compute-effective-method-function (gf methods))
    24592723(defmethod compute-effective-method-function ((gf standard-generic-function) methods)
    24602724  (std-compute-effective-method-function gf methods))