Changeset 548
- Timestamp:
- Feb 18, 2004, 10:51:29 AM (21 years ago)
- File:
-
- 1 edited
-
trunk/ccl/examples/objc-clos.lisp (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/ccl/examples/objc-clos.lisp
r543 r548 880 880 881 881 882 ;;; Return the generic function name and lambda list corresponding to 883 ;;; a given ObjC MSG 884 ;;; NOTE: Gary wants to handle "init..." messages specially 882 ;;; Return the generic function name, lambda list and keywords corresponding 883 ;;; to a given ObjC MSG 885 884 886 885 (defun gfify (msg) 887 (let ((mcomps (split-if-char #\: msg :elide))) 888 (values 889 (compute-lisp-name (first mcomps) (find-package "NS")) 890 (case (count #\: msg) 891 (0 '(self)) 892 (1 '(self arg)) 893 (t `(self arg &key ,@(mapcar #'compute-lisp-name (rest mcomps)))))))) 886 (let* ((mcomps (split-if-char #\: msg :elide)) 887 (ncolons (count #\: msg)) 888 (prefix (if (zerop ncolons) "@" ""))) 889 (values (compute-lisp-name 890 (if (zerop ncolons) 891 (string-cat prefix (first mcomps)) 892 (first mcomps)) 893 (find-package "NS")) 894 (if (zerop ncolons) '(self) '(self arg &key)) 895 (mapcar #'compute-lisp-name (rest mcomps))))) 896 897 898 ;;; Special dcode for ObjC generic functions 899 ;;; Currently, the list of keywords is used as the qualifier for an ObjC method 900 ;;; This dcode just scans the list of methods looking for one whose qualifer 901 ;;; matches the keywords in this call 902 903 (defun %%objc-dcode (dt args) 904 (flet ((invoke-method (largs) 905 (multiple-value-bind (keys vals) (keys-and-vals (cddr largs)) 906 (declare (ignore vals)) 907 (dolist (m (%gf-dispatch-table-methods dt)) 908 (when (equal (method-qualifiers m) keys) 909 (return-from %%objc-dcode (apply (method-function m) largs)))) 910 (apply #'no-applicable-method (%gf-dispatch-table-gf dt) largs)))) 911 ;; If only on arg is present, args is apparently not encoded 912 (if (numberp args) 913 (with-list-from-lexpr (l args) (invoke-method l)) 914 (invoke-method (list args))))) 894 915 895 916 … … 898 919 (defun ensure-objc-generic-function (msg) 899 920 (multiple-value-bind (gf-name lambda-list) (gfify msg) 900 (when (and (fboundp gf-name) (generic-function-p (symbol-function gf-name))) 901 (setq lambda-list 902 (generalize-lambda-list 903 (generic-function-lambda-list (symbol-function gf-name)) 904 lambda-list))) 905 (ensure-generic-function 906 gf-name 907 :lambda-list lambda-list 908 :generic-function-class (find-class 'objc-generic-function) 909 :method-class (find-class 'objc-method)))) 910 911 912 ;;; Generalize a lambda list of an existing objc generic function to be 913 ;;; consistent with a new lambda list 914 915 (defun generalize-lambda-list (oldll newll) 916 (if (equal oldll newll) 917 oldll 918 (let (req opt keys) 919 (multiple-value-bind (reqold optold keysold) 920 (parse-objc-gf-lambda-list oldll) 921 (multiple-value-bind (reqnew ignore keysnew) (parse-objc-gf-lambda-list newll) 922 (declare (ignore ignore)) 923 (setq opt optold) 924 (if (/= (length reqold) (length reqnew)) 925 (setq req '(self) opt '(arg)) 926 (setq req reqold)) 927 (setq keys (union keysold keysnew)) 928 `(,@req ,@(when opt (cons '&optional opt)) ,@(when keys (cons '&key keys)))))))) 929 930 (defun parse-objc-gf-lambda-list (ll) 931 (let ((optpos (position '&optional ll :test #'eq)) 932 (keypos (position '&key ll :test #'eq))) 933 (values 934 (subseq ll 0 (or optpos keypos)) 935 (if optpos (subseq ll (1+ optpos) keypos)) 936 (if keypos (subseq ll (1+ keypos)))))) 921 (let ((gf (ensure-generic-function 922 gf-name 923 :lambda-list lambda-list 924 :generic-function-class (find-class 'objc-generic-function) 925 :method-class (find-class 'objc-method)))) 926 (setf (%gf-dcode gf) #'%%objc-dcode) 927 gf))) 937 928 938 929 939 930 ;;; Ensure that the method corresponding to CLASS's method for MSG exists 940 931 941 (defun ensure-objc-method (msg class) 942 (multiple-value-bind (gf-name lambda-list) (gfify msg) 943 (let* ((keypos (position '&key lambda-list :test #'eq)) 944 (required-args (subseq lambda-list 0 keypos)) 945 (keyword-args 946 (if keypos (subseq lambda-list (1+ keypos)) nil))) 947 (ensure-objc-generic-function msg) 948 (ensure-method 949 gf-name 950 (cons (class-name class) 951 (make-list (1- (length required-args)) :initial-element t)) 952 :function 953 (compile nil 954 `(lambda ,lambda-list 955 ,(case (length lambda-list) 956 (1 `(send self ,msg)) 957 (2 `(send self ,msg arg)) 958 (t `(send self ,msg arg ,@(append keyword-args '(&allow-other-keys))))))) 959 :qualifiers nil 960 :lambda-list lambda-list)))) 932 (defun ensure-objc-method (msg &optional 933 (class (find-class 'objc:objc-object))) 934 (flet ((keywordify (sym) 935 (intern (string sym) (find-package 'keyword)))) 936 (multiple-value-bind (gf-name lambda-list keys) (gfify msg) 937 (let* ((ncolons (count #\: msg)) 938 (class-name (class-name class)) 939 (gf (ensure-objc-generic-function msg)) 940 (lambda-list (append lambda-list keys)) 941 (m 942 (ensure-method 943 gf-name 944 (if (zerop ncolons) (list class-name) (list class-name t)) 945 :function 946 (compile nil 947 `(lambda ,lambda-list 948 ,(case ncolons 949 (0 `(send self ,msg)) 950 (1 `(send self ,msg arg)) 951 (t `(send self ,msg arg ,@keys))))) 952 :qualifiers (mapcar #'keywordify keys) 953 :lambda-list lambda-list))) 954 (setf (%gf-dcode gf) #'%%objc-dcode) 955 m)))) 961 956 962 957 963 958 ;;; Someday, this might even work... 964 959 965 (defun define-all-objc- gfs ()960 (defun define-all-objc-methods () 966 961 (declare (special *type-signature-table*)) 967 962 (maphash #'(lambda (msg ignore) 968 963 (declare (ignore ignore)) 969 (ensure-objc- generic-functionmsg))964 (ensure-objc-method msg)) 970 965 *type-signature-table*)) 971 966 972 973 ;;; ISSUES974 ;;; - Generic function conflicts975 ;;; - Currently invokes compiler976 ;;; - How to handle messages requiring STRETs?977 ;;; - How to handle variable arity messages?
Note:
See TracChangeset
for help on using the changeset viewer.
