1
;; -*- coding: utf-8; mode: scheme -*-
5
;; Copyright (c) 2006 KOGURO, Naoki (naoki@koguro.net)
6
;; All rights reserved.
8
;; Redistribution and use in source and binary forms, with or without
9
;; modification, are permitted provided that the following conditions
12
;; 1. Redistributions of source code must retain the above copyright
13
;; notice, this list of conditions and the following disclaimer.
14
;; 2. Redistributions in binary form must reproduce the above copyright
15
;; notice, this list of conditions and the following disclaimer in the
16
;; documentation and/or other materials provided with the distribution.
17
;; 3. Neither the name of the authors nor the names of its contributors
18
;; may be used to endorse or promote products derived from this
19
;; software without specific prior written permission.
21
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27
;; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
;; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
;; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
(define-module c-wrapper.objc-ffi
40
(extend c-wrapper.c-ffi)
42
(c-load '("stdlib.h" "objc/objc-runtime.h" "objc/objc-class.h")
44
:compiled-lib "objc-ffilib")
57
(select-module c-wrapper.objc-ffi)
59
(with-module c-wrapper.c-ffi
60
(set! %c-load-framework
62
(or (and-let* ((filename (find-file-in-paths
63
name :paths (map (cut string-append
69
"Library/Frameworks/")
70
"/Library/Frameworks/"
71
"/System/Library/Frameworks/"))
72
:pred file-is-readable?)))
73
(c-load-library filename))
74
(errorf "framework ~a is not found" name)))))
76
(define c-load-framework (with-module c-wrapper.objc-ffi %c-load-framework))
78
(define method-pool (make-hash-table 'string=?))
79
(define ivar-pool (make-hash-table 'equal?))
82
(objc-string <id> str) )
84
(define (@selector name)
85
(sel_registerName (x->string name)))
87
(define (encode-objc-type c-type)
90
((equal? c-type <c-char>)
92
((equal? c-type <c-int>)
94
((equal? c-type <c-short>)
96
((equal? c-type <c-long>)
98
((equal? c-type <c-longlong>)
100
((equal? c-type <c-uchar>)
102
((equal? c-type <c-uint>)
104
((equal? c-type <c-ushort>)
106
((equal? c-type <c-ulong>)
108
((equal? c-type <c-ulonglong>)
110
((equal? c-type <c-float>)
112
((equal? c-type <c-double>)
114
((equal? c-type <c-void>)
116
((equal? c-type <id>)
118
((equal? c-type <Class>)
120
((equal? c-type <SEL>)
122
((is-a? c-type <c-array-meta>)
123
(format "[~a]" (encode-objc-type (element-type-of c-type))))
124
((is-a? c-type <c-struct-meta>)
126
(string-append (map (lambda (alist)
129
(encode-objc-type (cdr alist))))
130
(decl-alist-of c-type)))))
131
((is-a? c-type <c-union-meta>)
133
(string-append (map (lambda (alist)
135
(encode-objc-type (cdr alist))))
136
(decl-alist-of c-type)))))
139
((is-a? c-type <c-ptr-meta>)
140
(format "^~a" (encode-objc-type (orig-c-type-of c-type))))
147
(c-sizeof c-type)))))
150
(define (objc-lookup-class name)
151
(objc_lookUpClass (symbol->string name)))
153
(define (objc-register-method name type-list)
154
(hash-table-put! method-pool name type-list))
159
(define (objc-make-class name super-class-ptr)
160
(unless (nil? (objc-lookup-class name))
161
(errorf "Objective-C class '~a' is already exists." name))
162
(let ((root-class-ptr (do ((class-ptr super-class-ptr
163
(ref (deref class-ptr) 'super_class)))
164
((nil? (ref (deref class-ptr) 'super_class))
166
(new-class (deref (cast <Class>
167
(malloc (c-sizeof (c-struct 'objc_class))))))
168
(meta-class (deref (cast <Class>
169
(malloc (c-sizeof (c-struct 'objc_class)))))))
170
(set! (ref new-class 'isa) (ptr meta-class))
171
(set! (ref new-class 'info) CLS_CLASS)
172
(set! (ref meta-class 'info) CLS_META)
174
(set! (ref new-class 'name) (symbol->string name))
175
(set! (ref meta-class 'name) (symbol->string name))
177
(set! (ref new-class 'methodLists) (make-null-ptr))
178
(set! (ref meta-class 'methodLists) (make-null-ptr))
180
(set! (ref new-class 'super_class) super-class-ptr)
181
(set! (ref meta-class 'super_class) (ref (deref super-class-ptr) 'isa))
182
(set! (ref meta-class 'isa) (ref (deref root-class-ptr) 'isa))
184
(set! (ref new-class 'instance_size) (ref (deref super-class-ptr)
186
(set! (ref meta-class 'instance_size)
187
(ref (deref (ref meta-class 'super_class)) 'instance_size))
189
(objc_addClass (ptr new-class))
192
(define (objc-add-method class method-name ret-type arg-types proc)
193
(let ((selector (@selector method-name))
194
(method (make (c-struct 'objc_method)))
195
(method-list (make (c-struct 'objc_method_list))))
196
(set! (ref method 'method_name) selector)
197
(set! (ref method 'method_types)
198
(apply string-append (map encode-objc-type
199
(list* ret-type <id> <SEL> arg-types))))
200
(set! (ref method 'method_imp)
201
(cast (c-func-ptr ret-type (list* <id> <SEL> arg-types)) proc))
203
(set! (ref method-list 'method_count) 1)
204
(set! (ref (ref method-list 'method_list) 0) method)
206
(class_addMethods class (ptr method-list))))
208
(define (needs-objc_msgSend_stret? ret-type)
209
(define (composite-type? ret-type)
210
(or (is-a? ret-type <c-struct-meta>)
211
(is-a? ret-type <c-union-meta>)))
214
(composite-type? ret-type)
217
((not (composite-type? ret-type))
219
((< 8 (c-sizeof ret-type))
222
(let loop ((composite-type ret-type))
225
((composite-type? type)
227
((and (is-a? type <c-array-meta>)
228
(< 1 (size-of type)))
232
(map cdr (decl-alist-of composite-type))))))))
234
(define (%objc-msg-send obj super? selector-name . args)
235
(or (and-let* ((lst (hash-table-get method-pool selector-name)))
236
(let* ((ret-type (car lst))
237
(arg-types (cdr lst))
238
(send (if (needs-objc_msgSend_stret? ret-type)
239
(lambda (obj selector . args)
240
(let ((retval (make ret-type)))
241
(apply (make-c-func-vaargs
243
'objc_msgSendSuper_stret
246
(append (list (ptr <c-void>)
248
(ptr (c-struct 'objc_super))
252
(ptr retval) obj selector args)
254
(make-c-func-vaargs (if super?
258
(append (list (if super?
259
(ptr (c-struct 'objc_super))
263
(sel (@selector selector-name)))
265
(errorf "selector ~a is not found." selector-name)
266
(apply send obj sel args))))
267
(errorf "selector ~a is not found." selector-name)))
269
(define (args->selector-name args)
271
(string-join (map x->string
272
(filter (lambda (elem)
273
(or (symbol? elem) (keyword? elem)))
276
(if (= (length args) 1)
280
(define (filter-args args)
281
(remove (lambda (elem) (or (symbol? elem) (keyword? elem))) args))
283
(define-method object-apply ((obj <id>) . rest)
284
(apply %objc-msg-send obj #f (args->selector-name rest) (filter-args rest)))
286
(define-method object-apply ((obj (ptr (c-struct 'objc_super))) . rest)
287
(apply %objc-msg-send obj #t (args->selector-name rest) (filter-args rest)))
289
(define (make-super class obj)
290
(let ((data (make (c-struct 'objc_super))))
291
(set! (ref data 'receiver) obj)
292
(set! (ref data 'class)
293
(ref (deref (cast (ptr (c-struct 'objc_class)) class)) 'super_class))
296
(provide "c-wrapper/objc-ffi")