git.fiddlerwoaroof.com
readtable.lisp
da75eb42
 (in-package :objc-runtime)
 
116081f3
 #+ccl
 (defgeneric send-message (object message &rest args)
   (:method ((object ccl:macptr) (message (eql 'alloc)) &rest args)
     (apply #'objc-msg-send object (ensure-selector "alloc") args)))
 
6b08248f
 (defun read-until (test symbol-prefix &optional stop-before-chars)
   "Read from a string until"
   (lambda (s c b)
     (declare (ignore c b))
     (let ((class-name (coerce (loop for next-char = (peek-char nil s nil nil t)
9a92915d
                                     while next-char
                                     until (funcall test next-char)
                                     collect (read-char s t nil t)
                                     finally (when (and (not (member next-char
                                                                     stop-before-chars))
                                                        (funcall test next-char))
                                               (read-char s t nil t)))
6b08248f
 
                               'string)))
       `(,symbol-prefix ,class-name))))
 
60bee14d
 (defmacro objc-send (obj message return &rest args)
   (let* ((return-t (case return
                      (:nsstring :pointer)
                      (t return)))
          (result `(cffi:foreign-funcall "objc_msgSend"
                                         :pointer ,obj
                                         :pointer ,message
                                         ,@args
                                         ,return-t)))
     (case return
       (:nsstring `(objc-send ,result
                              (ensure-selector "UTF8String")
                              :string))
       (t result))))
 
9a92915d
 (defun read-objc-form (s char)
   (declare (ignore char))
60bee14d
   (let* ((info (read-delimited-list #\] s t))
          (safe-p (when (eql #\? (peek-char nil s nil #\p t))
                    (read-char s t nil t)))
          (return-t (case (peek-char nil s nil #\p t)
                      (#\# (read-char s t nil t) :int)
                      (#\& (read-char s t nil t) :pointer)
                      (#\@ (read-char s t nil t) :nsstring)
                      (#\b (read-char s t nil t) :bool)
                      (#\s (read-char s t nil t) :string)
                      (t                         :pointer))))
     (when info
       (destructuring-bind (obj message . args) info
         (if safe-p
             `(safe-objc-msg-send ,return-t ,obj ,message ,@args)
             `(objc-send ,obj ,message ,return-t ,@args))))))
9a92915d
 
da75eb42
 (named-readtables:defreadtable :objc-readtable
   (:merge :standard)
   (:syntax-from :standard #\) #\])
9a92915d
   (:macro-char #\[ 'read-objc-form nil)
da75eb42
   (:dispatch-macro-char #\# #\@
                         (lambda (s c b)
                           c b
6b08248f
                           (let ((class-name (coerce (loop for c = (peek-char nil s nil nil t)
9a92915d
                                                           until (or (null c)
                                                                     (serapeum:whitespacep c)
                                                                     (member c
                                                                             '(#\) #\(  #\[ #\])))
                                                           collect (read-char s t nil t))
da75eb42
                                                     'string)))
382ab041
                             `(ensure-class ,class-name))))
6b08248f
   (:macro-char #\@ :dispatch t)
   (:dispatch-macro-char #\@ #\( (read-until (serapeum:op (char= _ #\)))
                                             'ensure-selector))
   (:dispatch-macro-char #\@ #\" (read-until (serapeum:op (char= _ #\"))
                                             'make-nsstring)))