Ticket #66: run-d-m-c-20100802a.patch

File run-d-m-c-20100802a.patch, 20.8 KB (added by Mark Evenson, 14 years ago)

Integration of SACLA/XCL DEFINE-METHOD-COMBINATION

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

    diff -r a3068f2c8c13 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-short-defcombin (whole)
     766  (let* ((name (cadr whole))
     767         (documentation
     768          (getf (cddr whole) :documentation ""))
     769         (identity-with-one-arg
     770          (getf (cddr whole) :identity-with-one-argument nil))
     771         (operator
     772          (getf (cddr whole) :operator name)))
     773    `(progn
     774       (setf (get ',name 'method-combination-object)
     775             (make-short-method-combination
     776              :name ',name
     777              :operator ',operator
     778              :identity-with-one-argument ',identity-with-one-arg
     779              :documentation ',documentation))
     780       ',name)))
     781
     782;;;
     783;;; long form of define-method-combination (from Sacla and XCL)
     784;;;
     785(defun define-method-combination-type (name &rest initargs)
     786    (setf (get name 'method-combination-object)
     787          (apply 'make-long-method-combination initargs)))
     788
     789(defun method-group-p (selecter qualifiers)
     790  ;; selecter::= qualifier-pattern | predicate
     791  (etypecase selecter
     792    (list (or (equal selecter qualifiers)
     793              (let ((last (last selecter)))
     794                (when (eq '* (cdr last))
     795                  (let* ((prefix `(,@(butlast selecter) ,(car last)))
     796                         (pos (mismatch prefix qualifiers)))
     797                    (or (null pos) (= pos (length prefix))))))))
     798    ((eql *) t)
     799    (symbol (funcall (symbol-function selecter) qualifiers))))
     800
     801(defun check-variable-name (name)
     802  (flet ((valid-variable-name-p (name)
     803                                (and (symbolp name) (not (constantp name)))))
     804    (assert (valid-variable-name-p name))))
     805
     806(defun canonicalize-method-group-spec (spec)
     807  ;; spec ::= (name {qualifier-pattern+ | predicate} [[long-form-option]])
     808  ;; long-form-option::= :description description | :order order |
     809  ;;                     :required required-p
     810  ;; a canonicalized-spec is a simple plist.
     811  (let* ((rest spec)
     812         (name (prog2 (check-variable-name (car rest))
     813                 (car rest)
     814                 (setq rest (cdr rest))))
     815         (option-names '(:description :order :required))
     816         (selecters (let ((end (or (position-if #'(lambda (it)
     817                                                   (member it option-names))
     818                                                rest)
     819                                   (length rest))))
     820                      (prog1 (subseq rest 0 end)
     821                        (setq rest (subseq rest end)))))
     822         (description (getf rest :description ""))
     823         (order (getf rest :order :most-specific-first))
     824         (required-p (getf rest :required)))
     825    `(list :name ',name
     826           :predicate (lambda (qualifiers)
     827                        (loop for item in ',selecters
     828                          thereis (method-group-p item qualifiers)))
     829           :description ',description
     830           :order ,order
     831           :required ',required-p)))
     832
     833(defun extract-required-part (lambda-list)
     834  (flet ((skip (key lambda-list)
     835               (if (eq (first lambda-list) key)
     836                   (cddr lambda-list)
     837                   lambda-list)))
     838    (ldiff (skip '&environment (skip '&whole lambda-list))
     839           (member-if #'(lambda (it) (member it lambda-list-keywords))
     840                      lambda-list))))
     841
     842(defun extract-specified-part (key lambda-list)
     843  (case key
     844    ((&eval &whole)
     845     (list (second (member key lambda-list))))
     846    (t
     847     (let ((here (cdr (member key lambda-list))))
     848       (ldiff here
     849              (member-if #'(lambda (it) (member it lambda-list-keywords))
     850                         here))))))
     851
     852(defun extract-optional-part (lambda-list)
     853  (extract-specified-part '&optional lambda-list))
     854
     855(defun parse-define-method-combination-arguments-lambda-list (lambda-list)
     856  ;; Define-method-combination Arguments Lambda Lists
     857  ;; http://www.lispworks.com/reference/HyperSpec/Body/03_dj.htm
     858  (let ((required (extract-required-part lambda-list))
     859        (whole    (extract-specified-part '&whole    lambda-list))
     860        (optional (extract-specified-part '&optional lambda-list))
     861        (rest     (extract-specified-part '&rest     lambda-list))
     862        (keys     (extract-specified-part '&key      lambda-list))
     863        (aux      (extract-specified-part '&aux      lambda-list)))
     864    (values (first whole)
     865            required
     866            (mapcar #'(lambda (spec)
     867                       (if (consp spec)
     868                           `(,(first spec) ,(second spec) ,@(cddr spec))
     869                           `(,spec nil)))
     870                    optional)
     871            (first rest)
     872            (mapcar #'(lambda (spec)
     873                       (let ((key (if (consp spec) (car spec) spec))
     874                             (rest (when (consp spec) (rest spec))))
     875                         `(,(if (consp key) key `(,(make-keyword key) ,key))
     876                           ,(car rest)
     877                           ,@(cdr rest))))
     878                    keys)
     879            (mapcar #'(lambda (spec)
     880                       (if (consp spec)
     881                           `(,(first spec) ,(second spec))
     882                           `(,spec nil)))
     883                    aux))))
     884
     885(defmacro getk (plist key init-form)
     886  "Similar to getf except eval and return INIT-FORM if KEY has no value in PLIST."
     887  (let ((not-exist (gensym))
     888        (value (gensym)))
     889    `(let ((,value (getf ,plist ,key ,not-exist)))
     890       (if (eq ,not-exist ,value) ,init-form ,value))))
     891
     892(defconstant +gf-args-var+ (make-symbol "GF-ARGS-VAR"))
     893
     894(defmacro with-args-lambda-list (args-lambda-list generic-function-symbol
     895                                                  &body forms)
     896  (let ((gf-lambda-list (gensym))
     897        (nrequired (gensym))
     898        (noptional (gensym))
     899        (rest-args (gensym)))
     900    (multiple-value-bind (whole required optional rest keys aux)
     901        (parse-define-method-combination-arguments-lambda-list args-lambda-list)
     902      `(let* ((,gf-lambda-list (slot-value ,generic-function-symbol 'lambda-list))
     903              (,nrequired (length (extract-required-part ,gf-lambda-list)))
     904              (,noptional (length (extract-optional-part ,gf-lambda-list)))
     905              (,rest-args (subseq ,+gf-args-var+ (+ ,nrequired ,noptional)))
     906              ,@(when whole `((,whole ,+gf-args-var+)))
     907              ,@(loop for var in required and i upfrom 0
     908                  collect `(,var (when (< ,i ,nrequired)
     909                                   (nth ,i ,+gf-args-var+))))
     910              ,@(loop for (var init-form) in optional and i upfrom 0
     911                  collect
     912                  `(,var (if (< ,i ,noptional)
     913                             (nth (+ ,nrequired ,i) ,+gf-args-var+)
     914                             ,init-form)))
     915              ,@(when rest `((,rest ,rest-args)))
     916              ,@(loop for ((key var) init-form) in keys and i upfrom 0
     917                  collect `(,var (getk ,rest-args ',key ,init-form)))
     918              ,@(loop for (var init-form) in aux and i upfrom 0
     919                  collect `(,var ,init-form)))
     920         ,@forms))))
     921
     922(defmacro with-method-groups (method-group-specs methods-form &body forms)
     923  (flet ((grouping-form (spec methods-var)
     924                        (let ((predicate (coerce-to-function (getf spec :predicate)))
     925                              (group (gensym))
     926                              (leftovers (gensym))
     927                              (method (gensym)))
     928                          `(let ((,group '())
     929                                 (,leftovers '()))
     930                             (dolist (,method ,methods-var)
     931                               (if (funcall ,predicate (method-qualifiers ,method))
     932                                   (push ,method ,group)
     933                                   (push ,method ,leftovers)))
     934                             (ecase ,(getf spec :order)
     935                               (:most-specific-last )
     936                               (:most-specific-first (setq ,group (nreverse ,group))))
     937                             ,@(when (getf spec :required)
     938                                 `((when (null ,group)
     939                                     (error "Method group ~S must not be empty."
     940                                            ',(getf spec :name)))))
     941                             (setq ,methods-var (nreverse ,leftovers))
     942                             ,group))))
     943    (let ((rest (gensym))
     944          (method (gensym)))
     945      `(let* ((,rest ,methods-form)
     946              ,@(mapcar #'(lambda (spec)
     947                           `(,(getf spec :name) ,(grouping-form spec rest)))
     948                        method-group-specs))
     949         (dolist (,method ,rest)
     950           (invalid-method-error ,method
     951                                 "Method ~S with qualifiers ~S does not belong to any method group."
     952                                 ,method (method-qualifiers ,method)))
     953         ,@forms))))
     954
     955(defun method-combination-type-lambda
     956  (&key name lambda-list args-lambda-list generic-function-symbol
     957        method-group-specs declarations forms &allow-other-keys)
     958  (let ((methods (gensym)))
     959    `(lambda (,generic-function-symbol ,methods ,@lambda-list)
     960       ,@declarations
     961       (let ((*message-prefix* ,(format nil "METHOD COMBINATION TYPE ~S: " name)))
     962         (with-method-groups ,method-group-specs
     963           ,methods
     964           ,@(if (null args-lambda-list)
     965                 forms
     966                 `((with-args-lambda-list ,args-lambda-list
     967                     ,generic-function-symbol
     968                     ,@forms))))))))
     969
     970(defun declarationp (expr)
     971  (and (consp expr) (eq (car expr) 'DECLARE)))
     972
     973(defun long-form-method-combination-args (args)
     974  ;; define-method-combination name lambda-list (method-group-specifier*) args
     975  ;; args ::= [(:arguments . args-lambda-list)]
     976  ;;          [(:generic-function generic-function-symbol)]
     977  ;;          [[declaration* | documentation]] form*
     978  (let ((rest args))
     979    (labels ((nextp (key) (and (consp (car rest)) (eq key (caar rest))))
     980             (args-lambda-list ()
     981               (when (nextp :arguments)
     982                 (prog1 (cdr (car rest)) (setq rest (cdr rest)))))
     983             (generic-function-symbol ()
     984                (if (nextp :generic-function)
     985                    (prog1 (second (car rest)) (setq rest (cdr rest)))
     986                    (gensym)))
     987             (declaration* ()
     988               (let ((end (position-if-not #'declarationp rest)))
     989                 (when end
     990                   (prog1 (subseq rest 0 end) (setq rest (nthcdr end rest))))))
     991             (documentation? ()
     992               (when (stringp (car rest))
     993                 (prog1 (car rest) (setq rest (cdr rest)))))
     994             (form* () rest))
     995      (let ((declarations '()))
     996        `(:args-lambda-list ,(args-lambda-list)
     997                            :generic-function-symbol ,(generic-function-symbol)
     998                            :documentation ,(prog2 (setq declarations (declaration*))
     999                                              (documentation?))
     1000                            :declarations (,@declarations ,@(declaration*))
     1001                            :forms ,(form*))))))
     1002
     1003(defun define-long-form-method-combination (name lambda-list method-group-specs
     1004                                                 &rest args)
     1005  (let* ((initargs `(:name ,name
     1006                     :lambda-list ,lambda-list
     1007                     :method-group-specs ,method-group-specs
     1008                     ,@(long-form-method-combination-args args)))
     1009         (lambda-expression (apply #'method-combination-type-lambda initargs)))
     1010    (apply #'define-method-combination-type name
     1011           `(,@initargs
     1012;;              :function ,(compile nil lambda-expression)
     1013             :function ,(coerce-to-function lambda-expression)))
     1014    name))
     1015
     1016(defun expand-long-defcombin (name args)
     1017  (destructuring-bind (lambda-list method-groups &rest body) args
     1018    `(apply #'define-long-form-method-combination
     1019            ',name
     1020            ',lambda-list
     1021            (list ,@(mapcar #'canonicalize-method-group-spec method-groups))
     1022            ',body)))
     1023
     1024(defmacro define-method-combination (&whole form name &rest args)
    7721025  (if (and (cddr form)
    7731026           (listp (caddr form)))
    774       (expand-long-defcombin form)
     1027      (expand-long-defcombin name args)
    7751028      (expand-short-defcombin form)))
    7761029
     1030
    7771031(define-method-combination +      :identity-with-one-argument t)
    7781032(define-method-combination and    :identity-with-one-argument t)
    7791033(define-method-combination append :identity-with-one-argument nil)
     
    15801834         (primaries '())
    15811835         (arounds '())
    15821836         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.")))))
     1837         emf-form
     1838         (long-method-combination-p
     1839          (typep (get mc-name 'method-combination-object) 'long-method-combination)))
     1840    (unless long-method-combination-p
     1841      (dolist (m methods)
     1842        (let ((qualifiers (method-qualifiers m)))
     1843          (cond ((null qualifiers)
     1844                 (if (eq mc-name 'standard)
     1845                     (push m primaries)
     1846                     (error "Method combination type mismatch.")))
     1847                ((cdr qualifiers)
     1848                 (error "Invalid method qualifiers."))
     1849                ((eq (car qualifiers) :around)
     1850                 (push m arounds))
     1851                ((eq (car qualifiers) mc-name)
     1852                 (push m primaries))
     1853                ((memq (car qualifiers) '(:before :after)))
     1854                (t
     1855                 (error "Invalid method qualifiers."))))))
    15991856    (unless (eq order :most-specific-last)
    16001857      (setf primaries (nreverse primaries)))
    16011858    (setf arounds (nreverse arounds))
    16021859    (setf around (car arounds))
    1603     (when (null primaries)
     1860    (when (and (null primaries) (not long-method-combination-p))
    16041861      (error "No primary methods for the generic function ~S." gf))
    16051862    (cond
    16061863      (around
     
    16111868                   #'compute-effective-method-function)
    16121869               gf (remove around methods))))
    16131870         (setf emf-form
    1614 ;;;           `(lambda (args)
    1615 ;;;          (funcall ,(%method-function around) args ,next-emfun))
    1616                (generate-emf-lambda (%method-function around) next-emfun)
    1617                )))
     1871               (generate-emf-lambda (%method-function around) next-emfun))))
    16181872      ((eq mc-name 'standard)
    16191873       (let* ((next-emfun (compute-primary-emfun (cdr primaries)))
    16201874              (befores (remove-if-not #'before-method-p methods))
     
    16241878               (cond
    16251879                 ((and (null befores) (null reverse-afters))
    16261880                  (let ((fast-function (%method-fast-function (car primaries))))
    1627 
    16281881                    (if fast-function
    16291882                        (ecase (length (gf-required-args gf))
    16301883                          (1
     
    16351888                           #'(lambda (args)
    16361889                               (declare (optimize speed))
    16371890                               (funcall fast-function (car args) (cadr args)))))
    1638                         ;;                               `(lambda (args)
    1639                         ;;                                  (declare (optimize speed))
    1640                         ;;                                  (funcall ,(%method-function (car primaries)) args ,next-emfun))
    16411891                        (generate-emf-lambda (%method-function (car primaries))
    16421892                                             next-emfun))))
    16431893                 (t
    16441894                  (let ((method-function (%method-function (car primaries))))
    1645 
    16461895                    #'(lambda (args)
    16471896                        (declare (optimize speed))
    16481897                        (dolist (before befores)
     
    16511900                            (funcall method-function args next-emfun)
    16521901                          (dolist (after reverse-afters)
    16531902                            (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))
     1903      (long-method-combination-p
     1904       (let* ((mc-obj (get mc-name 'method-combination-object))
     1905              (function (long-method-combination-function mc-obj))
     1906              (arguments (long-method-combination-arguments mc-obj)))
     1907         (assert (typep mc-obj 'long-method-combination))
     1908         (assert function)
     1909         (setf emf-form
     1910               (lambda (args)
     1911                 (macrolet ((call-method (method)
     1912                              `(funcall method ,args)))
     1913                   (eval (apply function gf methods arguments)))))))
     1914      (t
     1915       (let ((mc-obj (get mc-name 'method-combination-object)))
     1916         (unless (typep mc-obj 'short-method-combination)
     1917           (error "Unsupported method combination type ~A."
     1918                  mc-name))
     1919         (let* ((operator (short-method-combination-operator mc-obj))
     1920                (ioa (short-method-combination-identity-with-one-argument mc-obj)))
     1921           (setf emf-form
     1922                 (if (and (null (cdr primaries))
     1923                          (not (null ioa)))
     1924                     (generate-emf-lambda (%method-function (car primaries)) nil)
     1925                     `(lambda (args)
     1926                        (,operator ,@(mapcar
     1927                                      (lambda (primary)
     1928                                        `(funcall ,(%method-function primary) args nil))
     1929                                      primaries)))))))))
     1930    (assert (not (null emf-form)))
     1931    (or #+nil (ignore-errors (autocompile emf-form))
    16721932        (coerce-to-function emf-form))))
    16731933
    16741934(defun generate-emf-lambda (method-function next-emfun)