Changeset 6684
- Timestamp:
- Jun 8, 2007, 3:15:38 PM (17 years ago)
- File:
-
- 1 edited
-
branches/ide-1.0/ccl/examples/objc-clos.lisp (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/ide-1.0/ccl/examples/objc-clos.lisp
r6610 r6684 511 511 512 512 (defun compute-foreign-slot-accessors (eslotd) 513 (let* ((ftype (foreign-slot-definition-foreign-type eslotd))) 513 (let* ((ftype (foreign-slot-definition-foreign-type eslotd)) 514 (ordinal (foreign-type-ordinal ftype))) 514 515 (etypecase ftype 515 516 (foreign-integer-type … … 538 539 (values #'%get-single-float #'%set-single-float)) 539 540 (foreign-pointer-type 540 ;; If we're pointing to a structure whose first field is 541 ;; a pointer to a structure named :OBJC_CLASS, we're of 542 ;; type :ID and can (fairly) safely use %GET-PTR. 543 ;; Otherwise, reference the field as a raw macptr. 544 (let* ((to (foreign-pointer-type-to ftype))) 545 (if 546 (and (typep to 'foreign-record-type) 547 (eq :struct (foreign-record-type-kind to)) 548 (progn 549 (ensure-foreign-type-bits to) 550 (let* ((first-field (car (foreign-record-type-fields to))) 551 (first-field-type 552 (if first-field 553 (foreign-record-field-type first-field)))) 554 (and (typep first-field-type 'foreign-pointer-type) 555 (let* ((first-to (foreign-pointer-type-to 556 first-field-type))) 557 (and (typep first-to 'foreign-record-type) 558 (eq :struct 559 (foreign-record-type-kind first-to)) 560 (eq :objc_class 561 (foreign-record-type-name first-to)))))))) 562 (values #'%get-ptr #'%set-ptr) 563 (values #'(lambda (ptr offset) 564 (let* ((p (%null-ptr))) 565 (%set-macptr-domain p 1) 566 (%setf-macptr p (%get-ptr ptr offset)))) 567 #'%set-ptr)))) 541 (if (objc-id-type-p ftype) 542 (values #'%get-ptr #'%set-ptr) 543 (let* ((to (foreign-pointer-type-to ftype)) 544 (to-ordinal (if to (foreign-type-ordinal to) 0))) 545 (values #'(lambda (ptr offset) 546 (let* ((p (%null-ptr))) 547 (%set-macptr-domain p 1) 548 (%set-macptr-type p to-ordinal) 549 (%setf-macptr p (%get-ptr ptr offset)))) 550 #'%set-ptr)))) 568 551 (foreign-mem-block-type 569 552 (let* ((nbytes (%foreign-type-or-record-size ftype :bytes))) 570 (values #'%inc-ptr #'(lambda (pointer offset new) 553 (values #'(lambda (ptr offset) 554 (let* ((p (%inc-ptr ptr offset))) 555 (%set-macptr-type p ordinal) 556 p)) 557 #'(lambda (pointer offset new) 571 558 (setf (%composite-pointer-ref 572 559 nbytes … … 905 892 906 893 907 ;;; This (interesting) code has never been enabled, and is (slightly) 908 ;;; broken by the new (lazy, declaration-based) implementation of SEND 909 ;;; and friends. 910 ;;; We probably want to un-break this (and figure out how to define 911 ;;; ObjC gf's in the new world), and some of the code for compiling 912 ;;; arbitrary message sends may be useful in other contexts. 913 914 #+objc-generic-functions 915 (progn 916 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 917 ;;;; Generic Function and Method Protocols ;;;; 918 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 919 920 ;;; The classes of ObjC generic functions and methods 921 922 (defclass objc-generic-function (standard-generic-function) 923 () 924 (:metaclass funcallable-standard-class)) 925 926 (defclass objc-method (standard-method) ()) 927 928 929 ;;; Return the generic function name, lambda list and keywords corresponding 930 ;;; to a given ObjC MSG 931 932 (defun gfify (msg) 933 (let* ((mcomps (split-if-char #\: msg :elide)) 934 (ncolons (count #\: msg)) 935 (prefix (if (zerop ncolons) "@" ""))) 936 (values (compute-lisp-name 937 (if (zerop ncolons) 938 (string-cat prefix (first mcomps)) 939 (first mcomps)) 940 (find-package "NS")) 941 (if (zerop ncolons) '(%self) '(%self %arg &key)) 942 (mapcar #'compute-lisp-name (rest mcomps))))) 943 944 945 ;;; Special dcode for ObjC generic functions 946 ;;; Currently, the list of keywords is used as the qualifier for an ObjC method 947 ;;; This dcode just scans the list of methods looking for one whose qualifer 948 ;;; matches the keywords in this call 949 950 (defun %%objc-dcode (dt args) 951 (flet ((invoke-method (largs) 952 (multiple-value-bind (keys vals) (keys-and-vals (cddr largs)) 953 (declare (ignore vals)) 954 (dolist (m (%gf-dispatch-table-methods dt)) 955 (when (equal (method-qualifiers m) keys) 956 (return-from %%objc-dcode (apply (method-function m) largs)))) 957 (apply #'no-applicable-method (%gf-dispatch-table-gf dt) largs)))) 958 ;; If only one arg is present, ARGS is apparently not encoded 959 (if (numberp args) 960 (with-list-from-lexpr (l args) (invoke-method l)) 961 (invoke-method (list args))))) 962 963 964 ;;; Ensure that the generic function corresponding to MSG exists 965 966 (defun ensure-objc-generic-function (msg) 967 (cond 968 ((null (message-descriptors msg)) 969 (error "Unknown ObjC message: ~S" msg)) 970 ((troublesome-message-p msg) nil) 971 (t 972 (multiple-value-bind (gf-name lambda-list) (gfify msg) 973 (let ((gf (ensure-generic-function 974 gf-name 975 :lambda-list lambda-list 976 :generic-function-class (find-class 'objc-generic-function) 977 :method-class (find-class 'objc-method)))) 978 (setf (%gf-dcode gf) #'%%objc-dcode) 979 gf))))) 980 981 982 ;;; Create the method function corresponding to the given ObjC MSG 983 984 (defun make-objc-method-function (msg lambda-list keys) 985 (let ((msgdescs (message-descriptors msg))) 986 (compile 987 nil 988 (if (= (length msgdescs) 1) 989 ;; The type signature is unique 990 `(lambda ,lambda-list 991 ,(build-message-send 992 msg (msg-desc-type-signature (first msgdescs)) keys)) 993 ;; The type signature is ambiguous 994 `(lambda ,lambda-list 995 (cond 996 ,@(loop for md in msgdescs 997 collect 998 `((or 999 ,@(loop for c in (msg-desc-classes md) 1000 collect 1001 `(typep %self ',(class-name c)))) 1002 (locally 1003 (declare (,(class-name (first (msg-desc-classes md))) 1004 %self)) 1005 ,(build-message-send 1006 msg (msg-desc-type-signature md) keys)))))))))) 1007 1008 1009 ;;; Build the message-sending code for the given message with the given 1010 ;;; type signature and keys 1011 1012 (defun build-message-send (msg tsig keys) 1013 (let* ((rvars nil) 1014 (args (if (zerop (count #\: msg)) 1015 nil 1016 (loop 1017 for a in (cons '%arg keys) 1018 for ftype in (rest tsig) 1019 for r/s-assoc = (coerceable-foreign-record-p ftype) 1020 for sname = (gensym) 1021 if r/s-assoc 1022 do (push (list sname (fudge-objc-type ftype)) rvars) 1023 and collect 1024 (generate-structure-to-foreign-record-copier-form 1025 (record-structure-association-structure-name r/s-assoc) 1026 (record-structure-association-record-name r/s-assoc) 1027 :struct-name a :record-name sname) 1028 else collect a)))) 1029 (if (requires-stret-p (first tsig)) 1030 ;; STRET message send 1031 (let ((r (gensym))) 1032 `(rlet ((,r ,(fudge-objc-type (first tsig))) ,@rvars) 1033 (send/stret ,r %self ,msg ,@args) 1034 ,(create-structure-from-record-form r (cadar tsig)))) 1035 ;; Normal message send 1036 `(rlet ,rvars 1037 (send %self ,msg ,@args))))) 1038 1039 1040 ;;; Ensure that the method corresponding to CLASS's method for MSG exists 1041 1042 (defun ensure-objc-method (msg) 1043 (cond 1044 ((null (message-descriptors msg)) 1045 (error "Unknown ObjC message: ~S" msg)) 1046 ((troublesome-message-p msg) nil) 1047 (t 1048 (flet ((keywordify (sym) 1049 (intern (string sym) (find-package 'keyword)))) 1050 (multiple-value-bind (gf-name lambda-list keys) (gfify msg) 1051 (let* ((gf (ensure-objc-generic-function msg)) 1052 (lambda-list (append lambda-list keys)) 1053 (m 1054 (ensure-method 1055 gf-name 1056 nil 1057 :function (make-objc-method-function msg lambda-list keys) 1058 :qualifiers (mapcar #'keywordify keys) 1059 :lambda-list lambda-list))) 1060 (setf (%gf-dcode gf) #'%%objc-dcode) 1061 m)))))) 1062 1063 1064 ;;; Generate ObjC methods for all messages in *TYPE-SIGNATURE-TABLE* 1065 1066 (defun define-all-objc-methods () 1067 (declare (special *type-signature-table*)) 1068 (maphash #'(lambda (msg ignore) 1069 (declare (ignore ignore)) 1070 (ensure-objc-method msg)) 1071 *type-signature-table*)) 1072 1073 1074 ;;; Lisp structures analogous to common Cocoa records 1075 1076 (defstruct (ns-range (:constructor make-ns-range (location length))) 1077 location 1078 length) 1079 1080 (defun ns-make-range (loc len) 1081 (make-ns-range loc len)) 1082 1083 (defstruct (ns-point (:constructor make-ns-point (x y))) 1084 x 1085 y) 1086 1087 (defun ns-make-point (x y) 1088 (make-ns-point (coerce x 'single-float) (coerce y 'single-float))) 1089 1090 (defstruct (ns-size (:constructor make-ns-size (width height))) 1091 width 1092 height) 1093 1094 (defun ns-make-size (w h) 1095 (make-ns-size 1096 (coerce w 'single-float) 1097 (coerce h 'single-float))) 1098 1099 ;;; Note that this is linear: four fields, rather than an ns-point 1100 ;;; and an ns-size. 1101 (defstruct (ns-rect 1102 (:constructor make-ns-rect 1103 (origin.x origin.y size.width size.height))) 1104 origin.x 1105 origin.y 1106 size.width 1107 size.height) 1108 1109 (defun ns-make-rect (ox oy sw sh) 1110 (make-ns-rect 1111 (coerce ox 'single-float) 1112 (coerce oy 'single-float) 1113 (coerce sw 'single-float) 1114 (coerce sh 'single-float))) 1115 1116 (defstruct (ns-decimal 1117 (:constructor make-ns-decimal 1118 (_exponent _length _is-negative _is-compact _reserved _mantissa))) 1119 _exponent 1120 _length 1121 _is-negative 1122 _is-compact 1123 _reserved 1124 _mantissa) 1125 1126 ;;; Also linear 1127 (defstruct (cg-rect 1128 (:constructor make-cg-rect 1129 (origin.x origin.y size.width size.height))) 1130 origin.x 1131 origin.y 1132 size.width 1133 size.height) 1134 1135 (defstruct (ns-affine-transform-struct 1136 (:constructor make-ns-affine-transform-struct 1137 (m11 m12 m21 m22 tx ty))) 1138 m11 m12 m21 m22 tx ty) 1139 1140 1141 (defun generate-foreign-record-to-structure-copier-form (record-type-name structure-class-name &key (struct-name (gensym)) (record-name (gensym))) 1142 (let* ((slot-names (mapcar #'slot-definition-name (class-slots (find-class structure-class-name)))) 1143 (record-type (%foreign-type-or-record record-type-name)) 1144 (accessor-names (foreign-record-accessor-names record-type))) 1145 (unless (eq (length slot-names) (length accessor-names)) 1146 (error "Slot names ~s don't match record accessors ~s" 1147 slot-names accessor-names)) 1148 (let* ((body (mapcar #'(lambda (slot-name accessor) 1149 `(setf (slot-value ,struct-name ',slot-name) 1150 ,(%foreign-access-form record-name 1151 record-type 1152 0 1153 accessor))) 1154 slot-names accessor-names))) 1155 `(progn ,@body ,struct-name)))) 1156 1157 (defun generate-structure-to-foreign-record-copier-form 1158 (structure-class-name record-type-name 1159 &key 1160 (struct-name (gensym)) 1161 (record-name (gensym))) 1162 (let* ((slot-names (mapcar #'slot-definition-name (class-slots (find-class structure-class-name)))) 1163 (record-type (%foreign-type-or-record record-type-name)) 1164 (accessor-names (foreign-record-accessor-names record-type))) 1165 (unless (eq (length slot-names) (length accessor-names)) 1166 (error "Slot names ~s don't match record accessors ~s" 1167 slot-names accessor-names)) 1168 (let* ((body (mapcar #'(lambda (slot-name accessor) 1169 `(setf ,(%foreign-access-form record-name 1170 record-type 1171 0 1172 accessor) 1173 (slot-value ,struct-name ',slot-name))) 1174 slot-names accessor-names))) 1175 `(progn ,@body ,record-name)))) 1176 1177 (defun generate-foreign-record-to-structure-creator-form 1178 (record-type-name constructor-name &key (record-name (gensym))) 1179 (let* ((record-type (%foreign-type-or-record record-type-name)) 1180 (accessor-names (foreign-record-accessor-names record-type)) 1181 (args (mapcar #'(lambda (accessor) 1182 (%foreign-access-form record-name 1183 record-type 1184 0 1185 accessor)) 1186 accessor-names))) 1187 `(,constructor-name ,@args))) 1188 1189 1190 (defstruct record-structure-association 1191 record-name 1192 structure-name 1193 structure-constructor-name) 1194 1195 (defparameter *record-structure-associations* ()) 1196 1197 (defun record-structure-association-from-record-name (r) 1198 (find r *record-structure-associations* :key #'record-structure-association-record-name)) 1199 1200 (defun need-record-structure-association-from-record-name (r) 1201 (or (record-structure-association-from-record-name r) 1202 (error "No lisp structure associated with foreign record named ~s" r))) 1203 1204 (defun record-structure-association-from-structure-name (r) 1205 (find r *record-structure-associations* :key #'record-structure-association-structure-name)) 1206 1207 (defun associate-record-with-structure (record-name structure-name constructor-name) 1208 (let* ((already-r (record-structure-association-from-record-name record-name)) 1209 (already-s (record-structure-association-from-structure-name structure-name)) 1210 (already (or already-r already-s)) 1211 (different (not (eq already-r already-s)))) 1212 (if already 1213 (if different 1214 (if already-r 1215 (error "~&Record named ~s is already associated with structure named ~s" 1216 (record-structure-association-record-name already-r) 1217 (record-structure-association-structure-name already-r)) 1218 (if already-s 1219 (error "~&Structure named ~s is already associated with record named ~s" 1220 (record-structure-association-structure-name already-s) 1221 (record-structure-association-record-name already-s)))) 1222 (setf (record-structure-association-structure-constructor-name already) 1223 constructor-name)) 1224 (push (make-record-structure-association 1225 :record-name record-name 1226 :structure-name structure-name 1227 :structure-constructor-name constructor-name) 1228 *record-structure-associations*)) 1229 t)) 1230 1231 (defun create-structure-from-record-form (var record-type) 1232 (let* ((a (need-record-structure-association-from-record-name 1233 record-type)) 1234 (constructor 1235 (record-structure-association-structure-constructor-name a))) 1236 (generate-foreign-record-to-structure-creator-form 1237 record-type constructor :record-name var))) 1238 1239 (defun coerceable-foreign-record-p (ftype) 1240 (and (consp ftype) 1241 (eq (first ftype) :struct) 1242 (find (second ftype) *record-structure-associations* 1243 :key #'record-structure-association-record-name))) 1244 1245 (associate-record-with-structure :_<NSR>ect 'ns-rect 'make-ns-rect) 1246 (associate-record-with-structure :_<NSP>oint 'ns-point 'make-ns-point) 1247 (associate-record-with-structure :_<NSS>ize 'ns-size 'make-ns-size) 1248 (associate-record-with-structure :_<NSR>ange 'ns-range 'make-ns-range) 1249 (associate-record-with-structure :<NSD>ecimal 'ns-decimal 'make-ns-decimal) 1250 (associate-record-with-structure :<CGR>ect 'cg-rect 'make-cg-rect) 1251 (associate-record-with-structure :_<NSA>ffine<T>ransform<S>truct 1252 'ns-affine-transform-struct 1253 'make-ns-affine-transform-struct) 1254 ) ; #+objc-generic-functions 894 ;;; By the time we see this, the slot name has been transformed to the form 895 ;;; "(load-time-value (ensure-slot-id <slot-name>))". 896 ;;; This only works if the setter is SETF inverse of the getter. 897 (define-compiler-macro slot-id-value (&whole call instance slot-name &environment env) 898 (or 899 (let* ((type nil)) 900 (if (and (symbolp instance) 901 (subtypep (setq type (cdr (assq 'type (nth-value 2 (variable-information instance env))))) 902 'objc:objc-object) 903 (consp slot-name) 904 (eq (car slot-name) 'load-time-value) 905 (consp (cdr slot-name)) 906 (null (cddr slot-name)) 907 (eq (caadr slot-name) 'ensure-slot-id) 908 (consp (cdadr slot-name)) 909 (null (cddadr slot-name)) 910 (setq slot-name (cadadr slot-name)) 911 (quoted-form-p slot-name) 912 (setq slot-name (cadr slot-name))) 913 (let* ((class (find-class type nil)) 914 (eslotd (when class (find slot-name (class-slots class) 915 :key #'slot-definition-name)))) 916 (when (typep eslotd 'foreign-effective-slot-definition) 917 (let* ((getter (foreign-slot-definition-getter eslotd)) 918 (name (if (typep getter 'compiled-function) 919 (function-name getter)))) 920 (when name 921 `(,name ,instance ,(slot-definition-location eslotd)))))))) 922 call)) 923 924
Note:
See TracChangeset
for help on using the changeset viewer.
