;;;; Objective-CL, an Objective-C bridge for Common Lisp. ;;;; Copyright (C) 2007, 2008 Matthias Andreas Benkard. ;;;; ;;;; This program is free software: you can redistribute it and/or ;;;; modify it under the terms of the GNU Lesser General Public License ;;;; as published by the Free Software Foundation, either version 3 of ;;;; the License, or (at your option) any later version. ;;;; ;;;; This program is distributed in the hope that it will be useful, but ;;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;;; Lesser General Public License for more details. ;;;; ;;;; You should have received a copy of the GNU Lesser General Public ;;;; License along with this program. If not, see ;;;; . (in-package #:mulk.objective-cl) #.(enable-method-syntax) (eval-when (:compile-toplevel :load-toplevel :execute) (find-objc-class "NSObject" t) (find-objc-class "NSString" t) (find-objc-class "NSArray" t) (find-objc-class "NSDictionary" t)) ;; May usefully override, among others: ;; - description (defclass ns::mlk-lisp-value (ns::ns-object lisp-value-wrapper-mixin) () #+(or) (:default-constructor new) (:metaclass ns::+ns-object)) (defvar *lisp-value-wrappers* (make-weak-value-hash-table)) (defun intern-lisp-value (value) ;; We need this function in order to preserve object identity on the ;; Objective-C side. As we want [(intern-lisp-value 10) self] to ;; return the FIXNUM 10, that is, a Lisp value rather than an ;; Objective-C instance, we cannot guarantee that ;; ;; (let ((x (intern-lisp-value y))) ;; (objc-eql x (invoke x 'self))) ;; ;; will evaluate to true unless we generally intern Lisp value ;; wrappers. (or (weak-gethash value *lisp-value-wrappers* nil) (setf (weak-gethash value *lisp-value-wrappers*) (make-lisp-value value)))) (defun make-lisp-value (value) ;; FIXME: The following won't work. Make MAKE-INSTANCE more useful... ;(make-instance 'ns::mlk-lisp-value :value value) (let* ((*skip-value-wrapper-unwrapping* t) (instance (invoke-by-name (typecase value (string (find-class 'ns::mlk-lisp-string)) (vector (find-class 'ns::mlk-lisp-array)) (list (find-class 'ns::mlk-lisp-list)) (t (find-class 'ns::mlk-lisp-value))) "new"))) (setf (lisp-value instance) value) instance)) ;; Must override: ;; - characterAtIndex: ;; - length ;; - replaceCharactersInRange:withString: ;; ;; May usefully override, among others: ;; - substringWithRange: (maybe) ;; - getCharacters:range: (for performance reasons) ;; - description (defclass ns::mlk-lisp-string (ns::ns-mutable-string lisp-value-wrapper-mixin) () (:metaclass ns::+ns-object)) ;; Must override: ;; - objectAtIndex: ;; - count ;; ;; May usefully override, among others: ;; - description (defclass ns::mlk-lisp-array (ns::ns-array lisp-value-wrapper-mixin) () (:metaclass ns::+ns-object)) ;; Must override: ;; - objectAtIndex: ;; - count ;; ;; May usefully override, among others: ;; - description (defclass ns::mlk-lisp-list (ns::mlk-lisp-array) () (:metaclass ns::+ns-object)) (define-objective-c-method #/description :id ((self ns::mlk-lisp-value)) (#/stringWithUTF8String: (find-objc-class 'ns-string) (format nil "" (write-to-string (lisp-value self) :readably nil :escape t :circle t :length 50 :level 5 :pretty nil :radix nil :base 10)))) (define-objective-c-method #/characterAtIndex: :short ((self ns::mlk-lisp-string) (index :unsigned-long)) ;; index is actually NSUInteger == ;; (:unsigned-long ((:nominally :unsigned-int))) on 32-bit architectures, ;; but (:unsigned-long ()) on 64-bit architectures. ;; ;; That is, it's word-sized and labeled `unsigned int' on 32-bit. (char-int (char (lisp-value self) index))) (define-objective-c-method #/length :unsigned-long ((self ns::mlk-lisp-string)) (length (lisp-value self))) (define-objective-c-method #/objectAtIndex: ((self ns::mlk-lisp-array) (index :unsigned-long)) (aref (lisp-value self) index)) (define-objective-c-method #/count ((self ns::mlk-lisp-array)) (length (lisp-value self))) #.(disable-method-syntax)