doc ffi/objc
svn: r12895
This commit is contained in:
parent
d1e5dd842e
commit
e3f008c691
|
@ -3,3 +3,5 @@
|
||||||
(define name "Sample FFIs")
|
(define name "Sample FFIs")
|
||||||
|
|
||||||
(define compile-omit-paths '("examples"))
|
(define compile-omit-paths '("examples"))
|
||||||
|
|
||||||
|
(define scribblings '(("objc.scrbl" (multi-page) (foreign))))
|
||||||
|
|
271
collects/ffi/objc.scrbl
Normal file
271
collects/ffi/objc.scrbl
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require scribble/manual
|
||||||
|
scribble/eval
|
||||||
|
(for-label scheme/base
|
||||||
|
scheme/foreign
|
||||||
|
ffi/objc))
|
||||||
|
|
||||||
|
@(define objc-eval (make-base-eval))
|
||||||
|
@(interaction-eval #:eval objc-eval (define-struct cpointer:id ()))
|
||||||
|
|
||||||
|
@(define seeCtype
|
||||||
|
@elem{see @secref[#:doc '(lib "scribblings/foreign/foreign.scrbl") "ctype"]})
|
||||||
|
|
||||||
|
@title{@bold{Objective-C} FFI}
|
||||||
|
|
||||||
|
@defmodule[ffi/objc]{The @schememodname[ffi/objc] library builds on
|
||||||
|
@schememodname[scheme/foreign] to support interaction with
|
||||||
|
@link["http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/"]{Objective-C}.}
|
||||||
|
|
||||||
|
The library supports Objective-C interaction in two layers. The upper
|
||||||
|
layer provides syntactic forms for sending messages and deriving
|
||||||
|
subclasses. The lower layer is a think wrapper on the
|
||||||
|
@link["http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/ObjCRuntimeRef/index.html"]{Objective-C
|
||||||
|
runtime library} functions. Even the upper layer is unsafe and
|
||||||
|
relatively low-level compared to normal Scheme libraries, because
|
||||||
|
argument and result types must be declared in terms of FFI C types
|
||||||
|
(@seeCtype).
|
||||||
|
|
||||||
|
@table-of-contents[]
|
||||||
|
|
||||||
|
@section{FFI Types and Constants}
|
||||||
|
|
||||||
|
@defthing[_id ctype?]{
|
||||||
|
|
||||||
|
The type of an Objective-C object, an opaque pointer.}
|
||||||
|
|
||||||
|
@defthing[_Class ctype?]{
|
||||||
|
|
||||||
|
The type of an Objective-C class, which is also an @scheme[_id].}
|
||||||
|
|
||||||
|
@defthing[_SEL ctype?]{
|
||||||
|
|
||||||
|
The type of an Objective-C selector, an opaque pointer.}
|
||||||
|
|
||||||
|
@defthing[_BOOL ctype?]{
|
||||||
|
|
||||||
|
The Objective-C boolean type. Scheme values are converted for C in the
|
||||||
|
usual way: @scheme[#f] is false and any other value is true. C values
|
||||||
|
are converted to Scheme booleans.}
|
||||||
|
|
||||||
|
@defthing[YES boolean?]{
|
||||||
|
|
||||||
|
Synonym for @scheme[#t]}
|
||||||
|
|
||||||
|
@defthing[NO boolean?]{
|
||||||
|
|
||||||
|
Synonym for @scheme[#f]}
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Syntactic Forms}
|
||||||
|
|
||||||
|
@defform*/subs[[(tell result-type obj-expr method-id)
|
||||||
|
(tell result-type obj-expr arg ...)]
|
||||||
|
([result-type code:blank
|
||||||
|
(code:line #:type ctype-expr)]
|
||||||
|
[arg (code:line method-id expr)
|
||||||
|
(code:line #:type ctype-expr method-id arg)])]{
|
||||||
|
|
||||||
|
Sends a message to the Objective-C object produced by
|
||||||
|
@scheme[obj-expr]. When a type is omitted for either the result or an
|
||||||
|
argument, the type is assumed to be @scheme[_id], otherwise it must
|
||||||
|
be specified as an FFI C type (@seeCtype).
|
||||||
|
|
||||||
|
If a single @scheme[method-id] is provided with no arguments, then
|
||||||
|
@scheme[method-id] must not end with @litchar{:}; otherwise, each
|
||||||
|
@scheme[method-id] must end with @litchar{:}.
|
||||||
|
|
||||||
|
@examples[
|
||||||
|
#:eval objc-eval
|
||||||
|
(eval:alts (tell NSString alloc) (make-cpointer:id))
|
||||||
|
(eval:alts (tell (tell NSString alloc)
|
||||||
|
initWithUTF8String: #:type _string "Hello")
|
||||||
|
(make-cpointer:id))
|
||||||
|
]}
|
||||||
|
|
||||||
|
@defform*[[(tellv obj-expr method-id)
|
||||||
|
(tellv obj-expr arg ...)]]{
|
||||||
|
|
||||||
|
Like @scheme[tell], but with a result type @scheme[_void].}
|
||||||
|
|
||||||
|
@defform[(import-class class-id ...)]{
|
||||||
|
|
||||||
|
Defines each @scheme[class-id] to the class (a value with FFI type
|
||||||
|
@scheme[_Class]) that is registered with the string form of
|
||||||
|
@scheme[class-id]. The registered class is obtained via
|
||||||
|
@scheme[objc_lookUpClass].
|
||||||
|
|
||||||
|
@examples[
|
||||||
|
#:eval objc-eval
|
||||||
|
(eval:alts (import-class NSString) (void))
|
||||||
|
]}
|
||||||
|
|
||||||
|
@defform/subs[#:literals (+ -)
|
||||||
|
(define-objc-class class-id superclass-expr
|
||||||
|
[field-id ...]
|
||||||
|
method)
|
||||||
|
([method (mode result-ctype-expr (method-id) body ...+)
|
||||||
|
(mode result-ctype-expr (arg ...+) body ...+)]
|
||||||
|
[mode + -]
|
||||||
|
[arg (code:line method-id [ctype-expr arg-id])])]{
|
||||||
|
|
||||||
|
Defines @scheme[class-id] as a new, registered Objective-C class (of
|
||||||
|
FFI type @scheme[_Class]). The @scheme[superclass-expr] should
|
||||||
|
produce an Objective-C class or @scheme[#f] for the superclass.
|
||||||
|
|
||||||
|
Each @scheme[field-id] is an instance field that holds a Scheme value
|
||||||
|
and that is initialized to @scheme[#f] when the object is
|
||||||
|
allocated. The @scheme[field-id]s can be referenced and @scheme[set!]
|
||||||
|
directly when the method @scheme[body]s. Outside the object, they can
|
||||||
|
be referenced and set with @scheme[get-ivar] and @scheme[set-ivar!].
|
||||||
|
|
||||||
|
Each @scheme[method] adds or overrides a method to the class (when
|
||||||
|
@scheme[mode] is @scheme[-]) to be called on instances, or it adds a
|
||||||
|
method to the meta-class (when @scheme[mode] is @scheme[+]) to be
|
||||||
|
called on the class itself. All result and argument types must be
|
||||||
|
declared using FFI C types (@seeCtype).
|
||||||
|
|
||||||
|
If a @scheme[method] is declared with a single @scheme[method-id] and
|
||||||
|
no arguments, then @scheme[method-id] must not end with
|
||||||
|
@litchar{:}. Otherwise, each @scheme[method-id] must end with
|
||||||
|
@litchar{:}.
|
||||||
|
|
||||||
|
If the special method @scheme[dealloc] is declared for mode
|
||||||
|
@scheme[-], it must not call the superclass method, because a
|
||||||
|
@scheme[(super-tell dealloc)] is added to the end of the method
|
||||||
|
automatically. In addition, before @scheme[(super-tell dealloc)],
|
||||||
|
space for each @scheme[field-id] within the instance is deallocated.
|
||||||
|
|
||||||
|
@examples[
|
||||||
|
#:eval objc-eval
|
||||||
|
(eval:alts
|
||||||
|
(define-objc-class MyView NSView
|
||||||
|
[bm] (code:comment #, @elem{<- one field})
|
||||||
|
(- _scheme (swapBitwmap: [_scheme new-bm])
|
||||||
|
(begin0 bm (set! bm new-bm)))
|
||||||
|
(- _void (drawRect: [#, @schemeidfont{_NSRect} exposed-rect])
|
||||||
|
(super-tell drawRect: exposed-rect)
|
||||||
|
(draw-bitmap-region bm exposed-rect))
|
||||||
|
(- _void (dealloc)
|
||||||
|
(when bm (done-with-bm bm))))
|
||||||
|
(void))
|
||||||
|
]}
|
||||||
|
|
||||||
|
@defidform[self]{
|
||||||
|
|
||||||
|
When used within the body of a @scheme[define-objc-class] method,
|
||||||
|
refers to the object whose method was called. This form cannot be used
|
||||||
|
outside of a @scheme[define-objc-class] method.}
|
||||||
|
|
||||||
|
@defform*[[(super-tell result-type method-id)
|
||||||
|
(super-tell result-type arg ...)]]{
|
||||||
|
|
||||||
|
When used within the body of a @scheme[define-objc-class] method,
|
||||||
|
calls a superclass method. The @scheme[result-type] and @scheme[arg]
|
||||||
|
sub-forms have the same syntax as in @scheme[tell]. This form cannot
|
||||||
|
be used outside of a @scheme[define-objc-class] method.}
|
||||||
|
|
||||||
|
|
||||||
|
@defform[(get-ivar obj-expr field-id)]{
|
||||||
|
|
||||||
|
Extracts the Scheme value of a field in a class created with
|
||||||
|
@scheme[define-objc-class].}
|
||||||
|
|
||||||
|
@defform[(set-ivar! obj-expr field-id value-expr)]{
|
||||||
|
|
||||||
|
Sets the Scheme value of a field in a class created with
|
||||||
|
@scheme[define-objc-class].}
|
||||||
|
|
||||||
|
@defform[(selector method-id)]{
|
||||||
|
|
||||||
|
Returns a selector (of FFI type @scheme[_SEL]) for the string form of
|
||||||
|
@scheme[method-id].
|
||||||
|
|
||||||
|
@examples[
|
||||||
|
(eval:alts (tellv button setAction: #:type _SEL (selector terminate:)) (void))
|
||||||
|
]}
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@section{Raw Runtime Functions}
|
||||||
|
|
||||||
|
@defproc[(objc_lookUpClass [s string?]) (or/c _Class #f)]{
|
||||||
|
|
||||||
|
Finds a registered class by name.}
|
||||||
|
|
||||||
|
@defproc[(sel_registerName [s string?]) _SEL]{
|
||||||
|
|
||||||
|
Interns a selector given its name in string form.}
|
||||||
|
|
||||||
|
@defproc[(objc_allocateClassPair [cls _Class] [s string?] [extra integer?])
|
||||||
|
_Class]{
|
||||||
|
|
||||||
|
Allocates a new Objective-C class.}
|
||||||
|
|
||||||
|
@defproc[(objc_registerClassPair [cls _Class]) void?]{
|
||||||
|
|
||||||
|
Registers an Objective-C class.}
|
||||||
|
|
||||||
|
@defproc[(object_getClass [obj _id]) _Class]{
|
||||||
|
|
||||||
|
Returns the class of an object (or the meta-class of a class).}
|
||||||
|
|
||||||
|
@defproc[(class_addMethod [cls _Class] [sel _SEL]
|
||||||
|
[imp procedure?]
|
||||||
|
[type ctype?]
|
||||||
|
[type-encoding string?])
|
||||||
|
boolean?]{
|
||||||
|
|
||||||
|
Adds a method to a class. The @scheme[type] argument must be a FFI C
|
||||||
|
type (@seeCtype) that matches both @scheme[imp] and and the not
|
||||||
|
Objective-C type string @scheme[type-encoding].}
|
||||||
|
|
||||||
|
@defproc[(class_addIvar [cls _Class] [name string?] [size exact-nonnegative-integer?]
|
||||||
|
[log-alignment exact-nonnegative-integer?] [type-encoding string?])
|
||||||
|
boolean?]{
|
||||||
|
|
||||||
|
Adds an instance variable to an Objective-C class.}
|
||||||
|
|
||||||
|
@defproc[(object_getInstanceVariable [obj _id]
|
||||||
|
[name string?])
|
||||||
|
(values _Ivar any/c)]{
|
||||||
|
|
||||||
|
Gets the value of an instance variable whose type is @scheme[_pointer].}
|
||||||
|
|
||||||
|
@defproc[(object_setInstanceVariable [obj _id]
|
||||||
|
[name string?]
|
||||||
|
[val any/c])
|
||||||
|
_Ivar]{
|
||||||
|
|
||||||
|
Sets the value of an instance variable whose type is @scheme[_pointer].}
|
||||||
|
|
||||||
|
@defthing[_Ivar ctype?]{
|
||||||
|
|
||||||
|
The type of an Objective-C instance variable, an opaque pointer.}
|
||||||
|
|
||||||
|
@defproc[((objc_msgSend/typed [types (vector/c result-ctype arg-ctype ...)])
|
||||||
|
[obj _id]
|
||||||
|
[sel _SEL]
|
||||||
|
[arg any/c])
|
||||||
|
any/c]{
|
||||||
|
|
||||||
|
Calls the Objective-C method on @scheme[_id] named by @scheme[sel].
|
||||||
|
The @scheme[types] vector must contain one more than the number of
|
||||||
|
supplied @scheme[arg]s; the first FFI C type in @scheme[type] is used
|
||||||
|
as the result type.}
|
||||||
|
|
||||||
|
@defproc[((objc_msgSendSuper/typed [types (vector/c result-ctype arg-ctype ...)])
|
||||||
|
[super _objc_super]
|
||||||
|
[sel _SEL]
|
||||||
|
[arg any/c])
|
||||||
|
any/c]{
|
||||||
|
|
||||||
|
Like @scheme[objc_msgSend/typed], but for a super call.}
|
||||||
|
|
||||||
|
@deftogether[(
|
||||||
|
@defproc[(make-obj_csuper [id _id] [super _Class]) _objc_super]
|
||||||
|
@defthing[_objc_super ctype?]
|
||||||
|
)]{
|
||||||
|
|
||||||
|
Constructor and FFI C type use for super calls.}
|
|
@ -20,7 +20,8 @@
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
|
|
||||||
(provide _id _BOOL _SEL)
|
(provide _id _Class _BOOL _SEL _Ivar
|
||||||
|
make-objc_super _objc_super)
|
||||||
|
|
||||||
(define _id (_cpointer/null 'id))
|
(define _id (_cpointer/null 'id))
|
||||||
|
|
||||||
|
@ -103,9 +104,9 @@
|
||||||
(syntax/loc stx (begin (import-class id) ...))]))
|
(syntax/loc stx (begin (import-class id) ...))]))
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
;; iget-value and iset-value work only with fields that contain Scheme values
|
;; iget-value and set-ivar! work only with fields that contain Scheme values
|
||||||
|
|
||||||
(provide iget-value iset-value)
|
(provide get-ivar set-ivar!)
|
||||||
|
|
||||||
(define-for-syntax (check-ivar ivar stx)
|
(define-for-syntax (check-ivar ivar stx)
|
||||||
(unless (identifier? ivar)
|
(unless (identifier? ivar)
|
||||||
|
@ -114,7 +115,7 @@
|
||||||
stx
|
stx
|
||||||
ivar)))
|
ivar)))
|
||||||
|
|
||||||
(define-syntax (iget-value stx)
|
(define-syntax (get-ivar stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
[(_ obj ivar)
|
[(_ obj ivar)
|
||||||
(begin
|
(begin
|
||||||
|
@ -127,7 +128,7 @@
|
||||||
(and p (ptr-ref p _scheme))))
|
(and p (ptr-ref p _scheme))))
|
||||||
|
|
||||||
|
|
||||||
(define-syntax (iset-value stx)
|
(define-syntax (set-ivar! stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
[(_ obj ivar val)
|
[(_ obj ivar val)
|
||||||
(begin
|
(begin
|
||||||
|
@ -254,7 +255,7 @@
|
||||||
arg)))
|
arg)))
|
||||||
(loop (cdr rest))))))))
|
(loop (cdr rest))))))))
|
||||||
|
|
||||||
(provide tell)
|
(provide tell tellv)
|
||||||
(define-for-syntax (build-send stx result-type send/typed send-args l-stx)
|
(define-for-syntax (build-send stx result-type send/typed send-args l-stx)
|
||||||
(let ([l (syntax->list l-stx)])
|
(let ([l (syntax->list l-stx)])
|
||||||
(with-syntax ([((tag type arg) ...) (parse-arg-list l stx #f)]
|
(with-syntax ([((tag type arg) ...) (parse-arg-list l stx #f)]
|
||||||
|
@ -299,6 +300,9 @@
|
||||||
#'objc_msgSend/typed #'(target)
|
#'objc_msgSend/typed #'(target)
|
||||||
#'(method/arg ...))]))
|
#'(method/arg ...))]))
|
||||||
|
|
||||||
|
(define-syntax-rule (tellv a ...)
|
||||||
|
(tell #:type _void a ...))
|
||||||
|
|
||||||
(define-for-syntax liftable-type?
|
(define-for-syntax liftable-type?
|
||||||
(let ([prims
|
(let ([prims
|
||||||
(syntax->list #'(_id _Class _SEL _void _int _long _float _double _double* _BOOL))])
|
(syntax->list #'(_id _Class _SEL _void _int _long _float _double _double* _BOOL))])
|
||||||
|
@ -377,11 +381,11 @@
|
||||||
(lambda (stx)
|
(lambda (stx)
|
||||||
(syntax-case stx (set!)
|
(syntax-case stx (set!)
|
||||||
[(set! _ val)
|
[(set! _ val)
|
||||||
(syntax/loc stx (iset-value self sym val))]
|
(syntax/loc stx (set-ivar! self sym val))]
|
||||||
[(_ arg ...)
|
[(_ arg ...)
|
||||||
(quasisyntax/loc stx (#,(quasisyntax/loc #'sym #'(iget-value self sym))
|
(quasisyntax/loc stx (#,(quasisyntax/loc #'sym #'(get-ivar self sym))
|
||||||
arg ...))]
|
arg ...))]
|
||||||
[_ (quasisyntax/loc #'sym (iget-value self sym))])))))
|
[_ (quasisyntax/loc #'sym (get-ivar self sym))])))))
|
||||||
|
|
||||||
(define (layout->string l)
|
(define (layout->string l)
|
||||||
(case l
|
(case l
|
||||||
|
|
|
@ -13,7 +13,7 @@ along with conversion functions to and from the existing types.
|
||||||
|
|
||||||
@; ----------------------------------------------------------------------
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
@section{Type Constructors}
|
@section[#:tag "ctype"]{Type Constructors}
|
||||||
|
|
||||||
@defproc[(make-ctype [type ctype?]
|
@defproc[(make-ctype [type ctype?]
|
||||||
[scheme-to-c (or/c #f (any/c . -> . any))]
|
[scheme-to-c (or/c #f (any/c . -> . any))]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user