Changeset 533


Ignore:
Timestamp:
Feb 13, 2004, 10:18:05 AM (21 years ago)
Author:
beer
Message:

Some initial steps toward integrating ObjC methods into CLOS generic functions

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ccl/examples/objc-clos.lisp

    r457 r533  
    1616;;;
    1717;;; TO DO
    18 ;;;  - Issues with OFFSET/LOCATION in foreign direct and effective slot definitions
    19 ;;;  - MAP-OBJC-CLASS needs to INITIALIZE-INSTANCE and FINALIZE-INHERITANCE
    20 ;;;    for predefined classes
    2118;;;  - Need to fully handle init keywords and ObjC init messages
    22 ;;;  - Need to add getter and setter functions for more foreign slot types
    2319;;;  - Canonicalization and retention for ObjC objects
    2420;;;  - Support redef of CLOS parts, but not changes in ObjC parts
     
    495491;;; Return the getter and setter functions for a foreign slot
    496492;;; NOTE: Should be changed to use FOREIGN-TYPE-TO-REPRESENTATION-TYPE
    497 
    498493
    499494(defun compute-foreign-slot-accessors (eslotd)
     
    715710                                                       class
    716711                                                       initargs))
    717             (apply #'%send ; For now; Use SEND macro eventually
    718                   (%send class 'alloc) (lisp-to-objc-init ks) vs))))
     712            ; The second %SEND below should be SEND eventually
     713            (apply #'%send (%send class 'alloc) (lisp-to-objc-init ks) vs))))
    719714    (unless (%null-ptr-p instance)
    720715      (let* ((len (length (%wrapper-instance-slots (class-own-wrapper class))))
     
    809804;;;;              Class Definition and Finalization Protocols               ;;;;
    810805;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    811 #|
    812 (defclass demo-view (ns:ns-view)
    813   ((x :foreign t)
    814    y
    815    (r :foreign t :type :<NSR>ect))
    816   (:metaclass ns:+ns-object))
    817 |#
    818806
    819807;;; Create the ObjC class/metaclass pair and dress it up in its minimal CLOS garb
    820808;;; This currently requires that exactly one of DIRECT-SUPERCLASSES be a
    821809;;; already existing subclass of OBJC:OBJC-CLASS
    822 
    823 
    824  
    825  
    826810
    827811(defun compute-objc-variable-name (sym)
     
    854838  t)
    855839
    856 (defmethod finalize-inheritance ((class objc:objc-class))
    857   ;; *** compute class precedence list
    858   ;; *** create effective slot definition objects
    859   )
    860 
    861840(defmethod make-instances-obsolete ((class objc:objc-class))
    862   ;; What should we do here?
    863841  class)
    864842
     
    875853  (declare (ignore initargs))
    876854  (find-class 'standard-reader-method))
     855
     856
     857;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     858;;;;                 Generic Function and Method  Protocols                 ;;;;
     859;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     860
     861;;; The classes of ObjC generic functions and methods
     862
     863(defclass objc-generic-function (standard-generic-function)
     864  ()
     865  (:metaclass funcallable-standard-class))
     866
     867(defclass objc-method (standard-method) ())
     868
     869
     870;;; Return the generic function name and lambda list corresponding to
     871;;; a given ObjC MSG
     872;;; NOTE: Gary wants to handle "init..." messages specially
     873
     874(defun gfify (msg)
     875  (let ((mcomps (split-if-char #\: msg :elide)))
     876    (values
     877     (compute-lisp-name (first mcomps) (find-package "NS"))
     878     (case (count #\: msg)
     879       (0 '(self))
     880       (1 '(self arg))
     881       (t `(self arg &key ,@(mapcar #'compute-lisp-name (rest mcomps))))))))
     882
     883
     884;;; Ensure that the generic function corresponding to MSG exists
     885
     886(defun ensure-objc-generic-function (msg)
     887  (multiple-value-bind (gf-name lambda-list) (gfify msg)           
     888    (when (and (fboundp gf-name) (generic-function-p (symbol-function gf-name)))
     889      (setq lambda-list
     890            (generalize-lambda-list
     891             (generic-function-lambda-list (symbol-function gf-name))
     892             lambda-list)))
     893    (ensure-generic-function
     894     gf-name
     895     :lambda-list lambda-list
     896     :generic-function-class (find-class 'objc-generic-function)
     897     :method-class (find-class 'objc-method))))
     898
     899
     900;;; Generalize a lambda list of an existing objc generic function to be
     901;;; consistent with a new lambda list
     902
     903(defun generalize-lambda-list (oldll newll)
     904  (if (equal oldll newll)
     905      oldll
     906    (let (req opt keys)
     907      (multiple-value-bind (reqold optold keysold)
     908                           (parse-objc-gf-lambda-list oldll)
     909        (multiple-value-bind (reqnew ignore keysnew) (parse-objc-gf-lambda-list newll)
     910          (declare (ignore ignore))
     911          (setq opt optold)
     912          (if (/= (length reqold) (length reqnew))
     913              (setq req '(self) opt '(arg))
     914            (setq req reqold))
     915          (setq keys (union keysold keysnew))
     916          `(,@req ,@(when opt (cons '&optional opt)) ,@(when keys (cons '&key keys))))))))
     917
     918(defun parse-objc-gf-lambda-list (ll)
     919  (let ((optpos (position '&optional ll :test #'eq))
     920        (keypos (position '&key ll :test #'eq)))
     921    (values
     922     (subseq ll 0 (or optpos keypos))
     923     (if optpos (subseq ll (1+ optpos) keypos))
     924     (if keypos (subseq ll (1+ keypos))))))
     925
     926
     927;;; Ensure that the method corresponding to CLASS's method for MSG exists
     928
     929(defun ensure-objc-method (msg class)
     930  (multiple-value-bind (gf-name lambda-list) (gfify msg)
     931    (let* ((keypos (position '&key lambda-list :test #'eq))
     932           (required-args (subseq lambda-list 0 keypos))
     933           (keyword-args
     934            (if keypos (subseq lambda-list (1+ keypos)) nil)))
     935      (ensure-objc-generic-function msg)
     936      (ensure-method
     937       gf-name
     938       (cons (class-name class)
     939             (make-list (1- (length required-args)) :initial-element t))
     940       :function
     941       (compile nil
     942         `(lambda ,lambda-list
     943            ,(case (length lambda-list)
     944               (1 `(send self ,msg))
     945               (2 `(send self ,msg arg))
     946               (t `(send self ,msg arg ,@(append keyword-args '(&allow-other-keys)))))))
     947       :qualifiers nil
     948       :lambda-list lambda-list))))
     949
     950
     951;;; Someday, this might even work...
     952
     953(defun define-all-objc-gfs ()
     954  (declare (special *type-signature-table*))
     955  (maphash #'(lambda (msg ignore)
     956               (declare (ignore ignore))
     957               (ensure-objc-generic-function msg))
     958           *type-signature-table*))
     959
     960
     961;;; ISSUES
     962;;;  - Generic function conflicts
     963;;;  - Currently invokes compiler
     964;;;  - How to handle messages requiring STRETs?
     965;;;  - How to handle variable arity messages?
Note: See TracChangeset for help on using the changeset viewer.