263 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Factor
		
	
	
			
		
		
	
	
			263 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Factor
		
	
	
| ! Copyright (C) 2006, 2010 Slava Pestov.
 | |
| ! See http://factorcode.org/license.txt for BSD license.
 | |
| USING: accessors alien alien.c-types alien.data alien.strings
 | |
| arrays assocs classes.struct cocoa.runtime cocoa.types
 | |
| combinators core-graphics.types fry generalizations
 | |
| io.encodings.utf8 kernel layouts libc locals macros make math
 | |
| memoize namespaces quotations sequences specialized-arrays
 | |
| stack-checker strings words ;
 | |
| QUALIFIED-WITH: alien.c-types c
 | |
| IN: cocoa.messages
 | |
| 
 | |
| SPECIALIZED-ARRAY: void*
 | |
| 
 | |
| : make-sender ( signature function -- quot )
 | |
|     [ over first , f , , second , \ alien-invoke , ] [ ] make ;
 | |
| 
 | |
| : sender-stub-name ( signature -- str )
 | |
|     first2 [ name>> ] [
 | |
|         [ name>> ] map "," join "(" ")" surround
 | |
|     ] bi* append "( sender-stub:" " )" surround ;
 | |
| 
 | |
| : sender-stub ( signature function -- word )
 | |
|     [ [ sender-stub-name f <word> dup ] keep ] dip
 | |
|     over first large-struct? [ "_stret" append ] when
 | |
|     make-sender dup infer define-declared ;
 | |
| 
 | |
| SYMBOL: message-senders
 | |
| SYMBOL: super-message-senders
 | |
| 
 | |
| message-senders [ H{ } clone ] initialize
 | |
| super-message-senders [ H{ } clone ] initialize
 | |
| 
 | |
| :: cache-stub ( signature function assoc -- )
 | |
|     signature assoc [ function sender-stub ] cache drop ;
 | |
| 
 | |
| : cache-stubs ( signature -- )
 | |
|     [ "objc_msgSendSuper" super-message-senders get cache-stub ]
 | |
|     [ "objc_msgSend" message-senders get cache-stub ]
 | |
|     bi ;
 | |
| 
 | |
| : <super> ( receiver -- super )
 | |
|     [ ] [ object_getClass class_getSuperclass ] bi
 | |
|     objc-super <struct-boa> ;
 | |
| 
 | |
| TUPLE: selector-tuple name object ;
 | |
| 
 | |
| MEMO: <selector> ( name -- sel ) f \ selector-tuple boa ;
 | |
| 
 | |
| : selector ( selector -- alien )
 | |
|     dup object>> expired? [
 | |
|         dup name>> sel_registerName
 | |
|         [ >>object drop ] keep
 | |
|     ] [
 | |
|         object>>
 | |
|     ] if ;
 | |
| 
 | |
| : lookup-selector ( name -- alien )
 | |
|     <selector> selector ;
 | |
| 
 | |
| SYMBOL: objc-methods
 | |
| 
 | |
| objc-methods [ H{ } clone ] initialize
 | |
| 
 | |
| ERROR: no-objc-method name ;
 | |
| 
 | |
| : ?lookup-method ( selector -- method/f )
 | |
|     objc-methods get at ;
 | |
| 
 | |
| : lookup-method ( selector -- method )
 | |
|     dup ?lookup-method [ ] [ no-objc-method ] ?if ;
 | |
| 
 | |
| : lookup-sender ( name -- method )
 | |
|     lookup-method message-senders get at ;
 | |
| 
 | |
| MEMO: make-prepare-send ( selector method super? -- quot )
 | |
|     [
 | |
|         [ \ <super> , ] when swap <selector> , \ selector ,
 | |
|     ] [ ] make
 | |
|     swap second length 2 - '[ _ _ ndip ] ;
 | |
| 
 | |
| MACRO: (send) ( selector super? -- quot )
 | |
|     [ dup lookup-method ] dip
 | |
|     [ make-prepare-send ] 2keep
 | |
|     super-message-senders message-senders ? get at
 | |
|     1quotation append ;
 | |
| 
 | |
| : send ( receiver args... selector -- return... ) f (send) ; inline
 | |
| 
 | |
| : super-send ( receiver args... selector -- return... ) t (send) ; inline
 | |
| 
 | |
| ! Runtime introspection
 | |
| SYMBOL: class-init-hooks
 | |
| 
 | |
| class-init-hooks [ H{ } clone ] initialize
 | |
| 
 | |
| : (objc-class) ( name word -- class )
 | |
|     2dup execute dup [ 2nip ] [
 | |
|         drop over class-init-hooks get at [ call( -- ) ] when*
 | |
|         2dup execute dup [ 2nip ] [
 | |
|             2drop "No such class: " prepend throw
 | |
|         ] if
 | |
|     ] if ; inline
 | |
| 
 | |
| : objc-class ( string -- class )
 | |
|     \ objc_getClass (objc-class) ;
 | |
| 
 | |
| : objc-protocol ( string -- class )
 | |
|     \ objc_getProtocol (objc-class) ;
 | |
| 
 | |
| : objc-meta-class ( string -- class )
 | |
|     \ objc_getMetaClass (objc-class) ;
 | |
| 
 | |
| SYMBOL: objc>alien-types
 | |
| 
 | |
| H{
 | |
|     { "c" c:char }
 | |
|     { "i" c:int }
 | |
|     { "s" c:short }
 | |
|     { "C" c:uchar }
 | |
|     { "I" c:uint }
 | |
|     { "S" c:ushort }
 | |
|     { "f" c:float }
 | |
|     { "d" c:double }
 | |
|     { "B" c:bool }
 | |
|     { "v" c:void }
 | |
|     { "*" c:void* }
 | |
|     { "?" unknown_type }
 | |
|     { "@" id }
 | |
|     { "#" Class }
 | |
|     { ":" SEL }
 | |
| }
 | |
| cell {
 | |
|     { 4 [ H{
 | |
|         { "l" c:long }
 | |
|         { "q" c:longlong }
 | |
|         { "L" c:ulong }
 | |
|         { "Q" c:ulonglong }
 | |
|     } ] }
 | |
|     { 8 [ H{
 | |
|         { "l" long32 }
 | |
|         { "q" long }
 | |
|         { "L" ulong32 }
 | |
|         { "Q" ulong }
 | |
|     } ] }
 | |
| } case
 | |
| assoc-union objc>alien-types set-global
 | |
| 
 | |
| SYMBOL: objc>struct-types
 | |
| 
 | |
| H{
 | |
|     { "_NSPoint" NSPoint }
 | |
|     { "NSPoint"  NSPoint }
 | |
|     { "CGPoint"  NSPoint }
 | |
|     { "_NSRect"  NSRect  }
 | |
|     { "NSRect"   NSRect  }
 | |
|     { "CGRect"   NSRect  }
 | |
|     { "_NSSize"  NSSize  }
 | |
|     { "NSSize"   NSSize  }
 | |
|     { "CGSize"   NSSize  }
 | |
|     { "_NSRange" NSRange }
 | |
|     { "NSRange"  NSRange }
 | |
| } objc>struct-types set-global
 | |
| 
 | |
| ! The transpose of the above map
 | |
| SYMBOL: alien>objc-types
 | |
| 
 | |
| objc>alien-types get [ swap ] assoc-map
 | |
| ! A hack...
 | |
| cell {
 | |
|     { 4 [ H{
 | |
|         { NSPoint    "{_NSPoint=ff}" }
 | |
|         { NSRect     "{_NSRect={_NSPoint=ff}{_NSSize=ff}}" }
 | |
|         { NSSize     "{_NSSize=ff}" }
 | |
|         { NSRange    "{_NSRange=II}" }
 | |
|         { NSInteger  "i" }
 | |
|         { NSUInteger "I" }
 | |
|         { CGFloat    "f" }
 | |
|     } ] }
 | |
|     { 8 [ H{
 | |
|         { NSPoint    "{CGPoint=dd}" }
 | |
|         { NSRect     "{CGRect={CGPoint=dd}{CGSize=dd}}" }
 | |
|         { NSSize     "{CGSize=dd}" }
 | |
|         { NSRange    "{_NSRange=QQ}" }
 | |
|         { NSInteger  "q" }
 | |
|         { NSUInteger "Q" }
 | |
|         { CGFloat    "d" }
 | |
|     } ] }
 | |
| } case
 | |
| assoc-union alien>objc-types set-global
 | |
| 
 | |
| : objc-struct-type ( i string -- ctype )
 | |
|     [ CHAR: = ] 2keep index-from swap subseq
 | |
|     objc>struct-types get at* [ drop void* ] unless ;
 | |
| 
 | |
| ERROR: no-objc-type name ;
 | |
| 
 | |
| : decode-type ( ch -- ctype )
 | |
|     1string dup objc>alien-types get at
 | |
|     [ ] [ no-objc-type ] ?if ;
 | |
| 
 | |
| : (parse-objc-type) ( i string -- ctype )
 | |
|     [ [ 1 + ] dip ] [ nth ] 2bi {
 | |
|         { [ dup "rnNoORV" member? ] [ drop (parse-objc-type) ] }
 | |
|         { [ dup CHAR: ^ = ] [ 3drop void* ] }
 | |
|         { [ dup CHAR: { = ] [ drop objc-struct-type ] }
 | |
|         { [ dup CHAR: [ = ] [ 3drop void* ] }
 | |
|         [ 2nip decode-type ]
 | |
|     } cond ;
 | |
| 
 | |
| : parse-objc-type ( string -- ctype ) 0 swap (parse-objc-type) ;
 | |
| 
 | |
| : method-arg-type ( method i -- type )
 | |
|     method_copyArgumentType
 | |
|     [ utf8 alien>string parse-objc-type ] keep
 | |
|     (free) ;
 | |
| 
 | |
| : method-arg-types ( method -- args )
 | |
|     dup method_getNumberOfArguments iota
 | |
|     [ method-arg-type ] with map ;
 | |
| 
 | |
| : method-return-type ( method -- ctype )
 | |
|     method_copyReturnType
 | |
|     [ utf8 alien>string parse-objc-type ] keep
 | |
|     (free) ;
 | |
| 
 | |
| : method-name ( method -- name )
 | |
|     method_getName sel_getName ;
 | |
| 
 | |
| : register-objc-method ( method -- )
 | |
|     [ method-name ]
 | |
|     [ [ method-return-type ] [ method-arg-types ] bi 2array ] bi
 | |
|     [ nip cache-stubs ] [ swap objc-methods get set-at ] 2bi ;
 | |
| 
 | |
| : each-method-in-class ( class quot -- )
 | |
|     [ { uint } [ class_copyMethodList ] with-out-parameters ] dip
 | |
|     over 0 = [ 3drop ] [
 | |
|         [ void* <c-direct-array> ] dip
 | |
|         [ each ] [ drop (free) ] 2bi
 | |
|     ] if ; inline
 | |
| 
 | |
| : register-objc-methods ( class -- )
 | |
|     [ register-objc-method ] each-method-in-class ;
 | |
| 
 | |
| : class-exists? ( string -- class ) objc_getClass >boolean ;
 | |
| 
 | |
| : define-objc-class-word ( quot name -- )
 | |
|     [ class-init-hooks get set-at ]
 | |
|     [
 | |
|         [ "cocoa.classes" create-word ] [ '[ _ objc-class ] ] bi
 | |
|         ( -- class ) define-declared
 | |
|     ] bi ;
 | |
| 
 | |
| : import-objc-class ( name quot -- )
 | |
|     2dup swap define-objc-class-word
 | |
|     over class-exists? [ drop ] [ call( -- ) ] if
 | |
|     dup class-exists? [
 | |
|         [ objc_getClass register-objc-methods ]
 | |
|         [ objc_getMetaClass register-objc-methods ] bi
 | |
|     ] [ drop ] if ;
 | |
| 
 | |
| : root-class ( class -- root )
 | |
|     dup class_getSuperclass [ root-class ] [ ] ?if ;
 |