I have a type definition...
typedef void *CXIndex;
which I believe reads "CXIndex is a pointer at void"
that is returned by...
CXIndex clang_createIndex(int x, int y)
This seems an obvious candidate to be a FFIOpaqueObject defined like this...
FFIOpaqueObject subclass: #CXIndex
instanceVariableNames: ''
classVariableNames: ''
package: 'LibclangPractice'
CXIndex class >> create
^ self ffiCall: #( CXIndex clang_createIndex ( 0, 0 ) )
however "CXIndex create inspect"
produces an error ==> FFIDereferencedOpaqueObjectError.
because..."external objects have a natural arity of zero but they MUST be
called with some arity,
because they are actually external addresses (pointers) and you need to
always declare external objects as this example:
self ffiCall: #( FFIExternalObject *c_function ( FFIExternalObject
*handle ) )
"
which is enforced by...
FFIOpaqueObjectType>>validateAfterParse: typeAndArityTuple
self pointerArity >= 1 ifTrue: [ ^ self ]. "@0"
typeAndArityTuple second >= 1 ifTrue: [ ^ self ].
FFIDereferencedOpaqueObjectError signal
where pointerArity seems set earlier just by counting the number of pointer
stars in the functions return type, which in this case is none...
FFICallout>>resolveType: aTypeName "aTypeName==> 'CXIndex' "
| name newName resolver binding ptrArity |
newName := aTypeName.
ptrArity := 0.
"resolve aliases and pointers"
[
name := newName asString trimRight.
newName := self aliasForType: name.
newName last = $* ifTrue: [
ptrArity := ptrArity + 1.
newName := newName allButLast ].
name = newName
] whileFalse.
resolver := requestor ifNil: [ self class ]. "resolver==> CXIndex
class"
binding := resolver ffiBindingOf: name asSymbol. "binding==>
#CXIndex->CXIndex"
binding ifNotNil: [
^ (binding value "@1" asExternalTypeOn: self) "@2" pointerArity:
ptrArity ] .
which @1 invokes...
CXIndex(FFIOpaqueObject) class >> asExternalTypeOn: generator
^ FFIOpaqueObjectType objectClass: self
FFIOpaqueObjectType(FFIExternalReferenceType) class >> objectClass: aClass
^ self new objectClass: aClass
FFIOpaqueObjectType(FFIExternalReferenceType) >> objectClass: aClass
objectClass := aClass. "aClass==>CXIndex"
pointerArity := 0. "actually this was done in #initialize" "@3"
Thus FFIOpaqueObjectType(CXIndex) is returned @2 which invokes...
FFIOpaqueObjectType(FFIExternalType)>>pointerArity: additionalArity
pointerArity := pointerArity + additionalArity.
which sets pointerArity ==> 0.
But I hazard to suggest that...
typedef void *CXIndex;
should make pointerArity:=1 when objectClass is assigned @3.
So I hacked around this by....
FFIExternalReference class >> pointerArity
^0
CXIndex class >> pointerArity
^1
FFIExternalReferenceType >> objectClass: aClass
objectClass := aClass.
pointerArity := aClass pointerArity.
but I wonder if this is the best way, or if external references these
opaque objects should have a class-side method similar to #fieldDesc
like...
typedef
^#( void * )
Thus CXIndex create "==> a CXIndex((void*)@ 16rB6D514A8)"
I am yet to test out this returned object by passing it to another
C-library function, but I thought the above was enough for one sitting.
cheers -ben
P.S. Further background...
Declarations...
typedef void *CXIndex;
CXIndex clang_createIndex(int xx, int yy));
defined at...
https://github.com/llvm-mirror/clang/blob/release_39/include/clang-c/Index.h
and definition is at...
https://github.com/llvm-mirror/clang/blob/release_39/include/clang-c/Index.h
extern "C" {
CXIndex clang_createIndex( ) {
...
CIndexer *CIdxr = new CIndexer();
...
return CIndexer;
} }