[PyObjC-svn] r2257 - in trunk/pyobjc/pyobjc-core: . Doc Lib/objc Modules/objc Modules/objc/test PyObjCTest
[email protected] Mon, 01 Jun 2009 05:02:15 -0500
| Newsgroups | gmane.comp.python.pyobjc.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: ronaldoussoren
Date: Mon Jun 1 05:02:14 2009
New Revision: 2257
Log:
* Clean up method signatures in the OC_ classes
* Initial support for Objective-C blocks, based on the documentation
in the clang repository.
This needs more testing, the unittests that are there are minimal,
but enough to let me think that block support actually works as
I like it to.
Added:
trunk/pyobjc/pyobjc-core/Doc/24blocks.txt
trunk/pyobjc/pyobjc-core/Modules/objc/block_support.h
trunk/pyobjc/pyobjc-core/Modules/objc/block_support.m
trunk/pyobjc/pyobjc-core/Modules/objc/test/block.m
trunk/pyobjc/pyobjc-core/PyObjCTest/test_blocks.py
Modified:
trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py
trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonNumber.m
trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.m
trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonString.m
trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonUnicode.m
trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m
trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.h
trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m
trunk/pyobjc/pyobjc-core/Modules/objc/method-signature.h
trunk/pyobjc/pyobjc-core/Modules/objc/module.m
trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m
trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.h
trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.m
trunk/pyobjc/pyobjc-core/Modules/objc/objc_support.m
trunk/pyobjc/pyobjc-core/Modules/objc/parsexml.m
trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h
trunk/pyobjc/pyobjc-core/NEWS.txt
trunk/pyobjc/pyobjc-core/setup.py
Modified: trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py (original)
+++ trunk/pyobjc/pyobjc-core/Lib/objc/_convenience.py Mon Jun 1 05:02:14 2009
@@ -17,7 +17,7 @@
set(['__cmp__'])
"""
-from _objc import setClassExtender, selector, lookUpClass, currentBundle, repythonify, splitSignature
+from _objc import setClassExtender, selector, lookUpClass, currentBundle, repythonify, splitSignature, _block_call
from itertools import imap
import sys
@@ -626,3 +626,11 @@
('__setslice__', NSMutableData__setslice__),
('__setitem__', NSMutableData__setitem__),
)
+
+
+def __call__(self, *args, **kwds):
+ return _block_call(self, self.__block_signature__, args, kwds)
+
+CLASS_METHODS['NSBlock'] = (
+ ('__call__', __call__),
+)
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonNumber.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonNumber.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonNumber.m Mon Jun 1 05:02:14 2009
@@ -450,25 +450,25 @@
#if 1
--(NSObject*)replacementObjectForArchiver:(NSObject*)archiver
+-(NSObject*)replacementObjectForArchiver:(NSArchiver*)archiver
{
(void)archiver;
return (NSObject*)self;
}
--(NSObject*)replacementObjectForKeyedArchiver:(NSObject*)archiver
+-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver
{
(void)archiver;
return (NSObject*)self;
}
--(NSObject*)replacementObjectForCoder:(NSObject*)archiver
+-(NSObject*)replacementObjectForCoder:(NSCoder*)archiver
{
(void)archiver;
return (NSObject*)self;
}
--(NSObject*)replacementObjectForPortCoder:(NSObject*)archiver
+-(NSObject*)replacementObjectForPortCoder:(NSPortCoder*)archiver
{
(void)archiver;
return (NSObject*)self;
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonObject.m Mon Jun 1 05:02:14 2009
@@ -1366,19 +1366,19 @@
return (NSObject*)self;
}
--(NSObject*)replacementObjectForKeyedArchiver:(NSObject*)archiver
+-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver
{
(void)archiver;
return (NSObject*)self;
}
--(NSObject*)replacementObjectForCoder:(NSObject*)archiver
+-(NSObject*)replacementObjectForCoder:(NSCoder*)archiver
{
(void)archiver;
return (NSObject*)self;
}
--(NSObject*)replacementObjectForPortCoder:(NSObject*)archiver
+-(NSObject*)replacementObjectForPortCoder:(NSPortCoder*)archiver
{
(void)archiver;
return (NSObject*)self;
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonString.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonString.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonString.m Mon Jun 1 05:02:14 2009
@@ -265,13 +265,13 @@
return self;
}
--(NSObject*)replacementObjectForCoder:(NSKeyedArchiver*)archiver
+-(NSObject*)replacementObjectForCoder:(NSCoder*)archiver
{
(void)(archiver);
return self;
}
--(NSObject*)replacementObjectForPortCoder:(NSKeyedArchiver*)archiver
+-(NSObject*)replacementObjectForPortCoder:(NSPortCoder*)archiver
{
(void)(archiver);
return self;
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonUnicode.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonUnicode.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/OC_PythonUnicode.m Mon Jun 1 05:02:14 2009
@@ -285,13 +285,13 @@
return self;
}
--(NSObject*)replacementObjectForCoder:(NSKeyedArchiver*)archiver
+-(NSObject*)replacementObjectForCoder:(NSCoder*)archiver
{
(void)(archiver);
return self;
}
--(NSObject*)replacementObjectForPortCoder:(NSKeyedArchiver*)archiver
+-(NSObject*)replacementObjectForPortCoder:(NSPortCoder*)archiver
{
(void)(archiver);
return self;
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/class-builder.m Mon Jun 1 05:02:14 2009
@@ -89,6 +89,11 @@
#endif
/* Special methods for Python subclasses of Objective-C objects */
+static void object_method_finalize(
+ ffi_cif* cif,
+ void* retval,
+ void** args,
+ void* userarg);
static void object_method_dealloc(
ffi_cif* cif,
void* retval,
@@ -333,6 +338,16 @@
preclass_addMethod( intermediate_class, @selector(dealloc),
(IMP)closure, "v@:");
+ methinfo = PyObjCMethodSignature_FromSignature("v@:");
+ if (methinfo == NULL) goto error_cleanup;
+ closure = PyObjCFFI_MakeClosure(methinfo, object_method_finalize,
+ base_class);
+ Py_DECREF(methinfo); methinfo = NULL;
+ if (closure == NULL) goto error_cleanup;
+
+ preclass_addMethod( intermediate_class, @selector(finalize),
+ (IMP)closure, "v@:");
+
methinfo = PyObjCMethodSignature_FromSignature("@@:@");
if (methinfo == NULL) goto error_cleanup;
closure = PyObjCFFI_MakeClosure(methinfo, object_method_valueForKey_,
@@ -671,6 +686,11 @@
} else {
need_intermediate = 1;
}
+ if (PyDict_GetItemString(class_dict, "finalize") == NULL) {
+ PyErr_Clear();
+ } else {
+ need_intermediate = 1;
+ }
if (PyDict_GetItemString(class_dict, "valueForKey_") == NULL) {
PyErr_Clear();
} else {
@@ -962,6 +982,11 @@
"v@:",
object_method_dealloc);
METH(
+ "finalize",
+ @selector(finalize),
+ "v@:",
+ object_method_finalize);
+ METH(
"storedValueForKey_",
@selector(storedValueForKey:),
"@@:@",
@@ -1342,6 +1367,54 @@
}
}
+/* -finalize */
+static void
+object_method_finalize(
+ ffi_cif* cif __attribute__((__unused__)),
+ void* retval __attribute__((__unused__)),
+ void** args,
+ void* userdata)
+{
+ id self = *(id*)(args[0]);
+ SEL _meth = *(SEL*)(args[1]);
+
+ struct objc_super spr;
+ PyObject* obj;
+ PyObject* delmethod;
+ PyObject* cls;
+ PyObject* ptype, *pvalue, *ptraceback;
+
+ PyObjC_BEGIN_WITH_GIL
+
+ PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+
+ cls = PyObjCClass_New(object_getClass(self));
+
+ delmethod = PyObjCClass_GetDelMethod(cls);
+ if (delmethod != NULL) {
+ PyObject* s = _PyObjCObject_NewDeallocHelper(self);
+ obj = PyObject_CallFunction(delmethod, "O", s);
+ _PyObjCObject_FreeDeallocHelper(s);
+ if (obj == NULL) {
+ PyErr_WriteUnraisable(delmethod);
+ } else {
+ Py_DECREF(obj);
+ }
+ Py_DECREF(delmethod);
+ }
+
+ free_ivars(self, cls);
+
+ PyErr_Restore(ptype, pvalue, ptraceback);
+
+ PyObjC_END_WITH_GIL
+
+ objc_superSetClass(spr, (Class)userdata);
+ objc_superSetReceiver(spr, self);
+
+ objc_msgSendSuper(&spr, _meth);
+}
+
/* -dealloc */
static void
object_method_dealloc(
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.h (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.h Mon Jun 1 05:02:14 2009
@@ -25,6 +25,10 @@
PyObject *PyObjCFFI_Caller(PyObject *aMeth, PyObject* self, PyObject *args);
void PyObjCFFI_FreeIMP(IMP imp);
+typedef void (*PyObjCBlockFunction)(void*, ...);
+PyObjCBlockFunction PyObjCFFI_MakeBlockFunction(PyObjCMethodSignature* sig, PyObject* callable);
+void PyObjCFFI_FreeBlockFunction(PyObjCBlockFunction value);
+
int PyObjCFFI_CountArguments(
PyObjCMethodSignature* methinfo, Py_ssize_t argOffset,
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/libffi_support.m Mon Jun 1 05:02:14 2009
@@ -972,11 +972,17 @@
* calls the python method and finally encodes the return value
*/
+enum closureType {
+ PyObjC_Function,
+ PyObjC_Method,
+ PyObjC_Block,
+};
+
typedef struct {
PyObject* callable;
int argCount;
PyObjCMethodSignature* methinfo;
- BOOL isMethod;
+ enum closureType closureType;
} _method_stub_userdata;
static void
@@ -1005,7 +1011,7 @@
arglist = PyList_New(0);
/* First translate from Objective-C to python */
- if (userdata->isMethod) {
+ if (userdata->closureType == PyObjC_Method) {
pyself = PyObjCObject_NewTransient(*(id*)args[0], &cookie);
if (pyself == NULL) {
goto error;
@@ -1018,6 +1024,9 @@
goto error;
}
startArg = 2;
+ } else if (userdata->closureType == PyObjC_Block) {
+ startArg = 1;
+ pyself = NULL;
} else {
startArg = 0;
pyself = NULL;
@@ -1308,7 +1317,7 @@
if (err == -1) {
if (res == Py_None) {
- if (userdata->isMethod) {
+ if (userdata->closureType == PyObjC_Method) {
PyErr_Format(PyExc_ValueError,
"%s: returned None, expecting "
"a value",
@@ -1330,7 +1339,7 @@
}
} else {
if (res != Py_None) {
- if (userdata->isMethod) {
+ if (userdata->closureType == PyObjC_Method) {
PyErr_Format(PyExc_ValueError,
"%s: did not return None, expecting "
"void return value",
@@ -1818,7 +1827,7 @@
stubUserdata->methinfo = methinfo;
Py_INCREF(methinfo);
- stubUserdata->isMethod = NO;
+ stubUserdata->closureType = PyObjC_Function;
if (callable) {
BOOL haveVarArgs = NO;
@@ -1846,7 +1855,8 @@
}
PyErr_Format(PyObjCExc_BadPrototypeError,
- "Not all Objective-C arguments are present in the Python argument-list of %s",
+ "Objective-C expects %"PY_FORMAT_SIZE_T"d arguments, Python argument has %d arguments for %s",
+ methinfo->ob_size, stubUserdata->argCount,
PyString_AsString(repr));
Py_DECREF(repr);
Py_DECREF(methinfo);
@@ -1901,7 +1911,7 @@
stubUserdata->methinfo = methinfo;
Py_INCREF(methinfo);
- stubUserdata->isMethod = YES;
+ stubUserdata->closureType = PyObjC_Method;
if (callable) {
BOOL haveVarArgs = NO;
@@ -1925,7 +1935,8 @@
}
PyErr_Format(PyObjCExc_BadPrototypeError,
- "Not all Objective-C arguments are present in the Python argument-list of %s",
+ "Objective-C expects %"PY_FORMAT_SIZE_T"d arguments, Python argument has %d arguments for %s",
+ methinfo->ob_size - 1, stubUserdata->argCount,
PyString_AsString(repr));
Py_DECREF(repr);
Py_DECREF(methinfo);
@@ -2016,6 +2027,85 @@
}
}
+
+PyObjCBlockFunction
+PyObjCFFI_MakeBlockFunction(PyObjCMethodSignature* methinfo, PyObject* callable)
+{
+ _method_stub_userdata* stubUserdata;
+ PyObjCBlockFunction closure;
+
+ stubUserdata = PyMem_Malloc(sizeof(*stubUserdata));
+ if (stubUserdata == NULL) {
+ return NULL;
+ }
+
+ stubUserdata->methinfo = methinfo;
+ Py_INCREF(methinfo);
+ stubUserdata->closureType = PyObjC_Block;
+
+ if (callable) {
+ BOOL haveVarArgs = NO;
+ BOOL haveVarKwds = NO;
+ stubUserdata->argCount = _argcount(callable, &haveVarArgs, &haveVarKwds);
+ if (stubUserdata->argCount == -1) {
+ Py_DECREF(methinfo);
+ PyMem_Free(stubUserdata);
+ return NULL;
+ }
+
+ if (stubUserdata->argCount == methinfo->ob_size -1 && !haveVarArgs && !haveVarKwds) {
+ /* OK */
+ } else if ((stubUserdata->argCount <= 1) && haveVarArgs && haveVarKwds) {
+ /* OK */
+ } else {
+ /* Wrong number of arguments, raise an error */
+ PyObject* repr = PyObject_Repr(callable);
+ if (repr == NULL) {
+ return NULL;
+ }
+
+ PyErr_Format(PyObjCExc_BadPrototypeError,
+ "Objective-C expects %"PY_FORMAT_SIZE_T"d arguments, Python argument has %d arguments for %s",
+ methinfo->ob_size - 1, stubUserdata->argCount,
+ PyString_AsString(repr));
+ Py_DECREF(repr);
+ Py_DECREF(methinfo);
+ PyMem_Free(stubUserdata);
+ return NULL;
+ }
+
+ stubUserdata->callable = callable;
+ Py_INCREF(stubUserdata->callable);
+ } else {
+ stubUserdata->callable = NULL;
+ stubUserdata->argCount = 0;
+ }
+
+ closure = (PyObjCBlockFunction)PyObjCFFI_MakeClosure(methinfo, method_stub, stubUserdata);
+ if (closure == NULL) {
+ Py_DECREF(methinfo);
+ if (stubUserdata->callable) {
+ Py_DECREF(stubUserdata->callable);
+ }
+ PyMem_Free(stubUserdata);
+ return NULL;
+ }
+
+ return closure;
+}
+
+void
+PyObjCFFI_FreeBlockFunction(PyObjCBlockFunction imp)
+{
+ _method_stub_userdata* userdata = PyObjCFFI_FreeClosure((IMP)imp);
+
+ if (userdata) {
+ Py_XDECREF(userdata->methinfo);
+ Py_DECREF(userdata->callable);
+ PyMem_Free(userdata);
+ }
+}
+
/* Count the number of arguments and their total size */
/* argument_size is not cleared and should be initialized to the amount of
* bufferspace that will be allocated just before the argument array
@@ -2372,9 +2462,6 @@
/* Encode argument, maybe after allocating space */
if (argtype[0] == _C_OUT) argtype ++; /* XXX: is this correct ???? */
-#if 0
- if (argtype[0] == 'O') argtype ++;
-#endif
argument = PyTuple_GET_ITEM (args, py_arg);
switch (*argtype) {
@@ -2779,6 +2866,33 @@
/* FALL THROUGH */
}
+
+ case _C_ID:
+ if (argtype[1] == '?') {
+ /* Argument is a block */
+ if (methinfo->argtype[i].callable == NULL) {
+ PyErr_Format(PyExc_TypeError, "Argument %"PY_FORMAT_SIZE_T"d is a block, but no signature available", i);
+ return -1;
+ }
+ argbuf_cur = align(argbuf_cur, PyObjCRT_AlignOfType(argtype));
+ arg = argbuf + argbuf_cur;
+ argbuf_cur += PyObjCRT_SizeOfType(argtype);
+ PyObjC_Assert(argbuf_cur <= argbuf_len, -1);
+ *(void**)arg = PyObjCBlock_Create(
+ methinfo->argtype[i].callable, argument);
+ if (*(void**)arg == NULL) {
+ return -1;
+ }
+ byref_attr[i].buffer = PyCObject_FromVoidPtr(
+ *(void**)arg,
+ (void(*)(void*))PyObjCBlock_Release);
+ arglist[i] = signature_to_ffi_type(argtype);
+ values[i] = arg;
+
+ break;
+ }
+ /* else: fallthrough */
+
default:
argbuf_cur = align(argbuf_cur, PyObjCRT_AlignOfType(argtype));
arg = argbuf + argbuf_cur;
@@ -2859,9 +2973,6 @@
} else {
/* Encode argument, maybe after allocating space */
if (argtype[0] == _C_OUT) argtype ++;
-#if 0
- if (argtype[0] == 'O') argtype ++;
-#endif
argument = PyTuple_GET_ITEM (args, py_arg);
py_arg ++;
@@ -3155,6 +3266,15 @@
return NULL;
}
+ if (tp[0] == _C_ID && tp[1] == '?') {
+ if (methinfo->rettype.callable != NULL) {
+ if (PyObjCObject_IsBlock(objc_result) && PyObjCObject_GetBlock(objc_result) == NULL) {
+ PyObjCObject_SET_BLOCK(objc_result, methinfo->rettype.callable);
+ Py_INCREF(methinfo->rettype.callable);
+ }
+ }
+ }
+
if (methinfo->rettype.alreadyRetained) {
if (PyObjCObject_Check(objc_result)) {
/* pythonify_c_return_value has retained the object, but we already
@@ -3240,6 +3360,14 @@
switch (methinfo->argtype[i].ptrType) {
case PyObjC_kPointerPlain:
v = pythonify_c_value(resttype, arg);
+ if (resttype[0] == _C_ID && resttype[1] == '?') {
+ if (methinfo->argtype[i].callable != NULL) {
+ if (PyObjCObject_IsBlock(v) && PyObjCObject_GetBlock(v) == NULL) {
+ PyObjCObject_SET_BLOCK(v, methinfo->argtype[i].callable);
+ Py_INCREF(methinfo->argtype[i].callable);
+ }
+ }
+ }
if (methinfo->argtype[i].alreadyRetained && PyObjCObject_Check(v)) {
[PyObjCObject_GetObject(v) release];
}
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/method-signature.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/method-signature.h (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/method-signature.h Mon Jun 1 05:02:14 2009
@@ -17,6 +17,7 @@
#include "pyobjc.h"
extern PyTypeObject PyObjCMethodSignature_Type;
+#define PyObjCMethodSignature_Check(obj) PyObject_TypeCheck(obj, &PyObjCMethodSignature_Type)
enum _PyObjC_PointerType {
PyObjC_kPointerPlain = 0,
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/module.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/module.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/module.m Mon Jun 1 05:02:14 2009
@@ -1718,6 +1718,9 @@
{ "_objc_sync_notifyAll", (PyCFunction)PyObjC_objc_sync_notifyAll,
METH_VARARGS,
"notify a all threads waiting for mutex for an object" },
+ { "_block_call", (PyCFunction)PyObjCBlock_Call,
+ METH_VARARGS,
+ "_block_call(block, signature, args, kwds) -> retval" },
{ 0, 0, 0, 0 } /* sentinel */
@@ -1800,6 +1803,11 @@
return;
}
+ if (PyObjCBlock_Setup() == -1) {
+ return;
+ }
+
+
PyType_Ready(&PyObjCClass_Type);
PyType_Ready((PyTypeObject*)&PyObjCObject_Type);
PyType_Ready(&PyObjCSelector_Type);
@@ -1835,6 +1843,7 @@
m = Py_InitModule4("_objc", mod_methods, NULL,
NULL, PYTHON_API_VERSION);
+
d = PyModule_GetDict(m);
/* use PyDict_SetItemString for the retain, non-heap types can't be dealloc'ed */
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc-class.m Mon Jun 1 05:02:14 2009
@@ -1405,6 +1405,13 @@
} else if (strcmp(className, "NSMutableData") == 0) {
((PyTypeObject *)result)->tp_as_buffer = &nsmutabledata_as_buffer;
}
+ if (strcmp(className, "NSBlock") == 0) {
+ ((PyTypeObject *)result)->tp_basicsize = sizeof(PyObjCBlockObject);
+ ((PyTypeObject *)result)->tp_call = PyObjCBlock_Call;
+ PyType_Modified((PyTypeObject*)result);
+ PyType_Ready((PyTypeObject *)result);
+ }
+
var = class_getInstanceVariable(objc_class, "__dict__");
if (var != NULL) {
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.h (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.h Mon Jun 1 05:02:14 2009
@@ -8,12 +8,22 @@
#define PyObjCObject_kSHOULD_NOT_RELEASE 0x08
#define PyObjCObject_kMAGIC_COOKIE 0x10
#define PyObjCObject_kCFOBJECT 0x20
+#define PyObjCObject_kBLOCK 0x40
+
typedef struct {
PyObject_HEAD
__strong id objc_object;
int flags;
} PyObjCObject;
+typedef struct {
+ PyObject_HEAD
+ __strong id objc_object;
+ int flags;
+ PyObjCMethodSignature* signature;
+} PyObjCBlockObject;
+
+
extern PyObjCClassObject PyObjCObject_Type;
#define PyObjCObject_Check(obj) PyObject_TypeCheck(obj, (PyTypeObject*)&PyObjCObject_Type)
@@ -26,6 +36,9 @@
PyObject* _PyObjCObject_NewDeallocHelper(id objc_object);
#define PyObjCObject_GetFlags(object) (((PyObjCObject*)(object))->flags)
#define PyObjCObject_IsClassic(object) (PyObjCObject_GetFlags(object) & PyObjCObject_kCLASSIC)
+#define PyObjCObject_IsBlock(object) (PyObjCObject_GetFlags(object) & PyObjCObject_kBLOCK)
+#define PyObjCObject_GetBlock(object) (((PyObjCBlockObject*)(object))->signature)
+#define PyObjCObject_SET_BLOCK(object, value) (((PyObjCBlockObject*)(object))->signature = (value))
PyObject* PyObjCObject_NewTransient(id objc_object, int* cookie);
void PyObjCObject_ReleaseTransient(PyObject* proxy, int cookie);
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc-object.m Mon Jun 1 05:02:14 2009
@@ -146,6 +146,13 @@
PyObject* ptype, *pvalue, *ptraceback;
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+ if (PyObjCObject_IsBlock(obj)) {
+ PyObjCMethodSignature* v = PyObjCObject_GetBlock(obj);
+ Py_XDECREF(v);
+ PyObjCObject_SET_BLOCK(obj, NULL);
+ }
+
+
if (PyObjCObject_GetFlags(obj) != PyObjCObject_kDEALLOC_HELPER
&& PyObjCObject_GetObject(obj) != nil) {
/* Release the proxied object, we don't have to do this when
@@ -491,7 +498,7 @@
obj_name = nil;
if (((PyObjCClassObject*)tp)->useKVO) {
if ((PyObjCObject_GetFlags(obj) & PyObjCObject_kUNINITIALIZED) == 0) {
- obj_name = [NSString stringWithCString:PyString_AS_STRING(name)];
+ obj_name = [NSString stringWithUTF8String:PyString_AS_STRING(name)];
_UseKVO((NSObject *)obj_inst, obj_name, YES);
}
}
@@ -588,6 +595,47 @@
return PyObjCMethodAccessor_New((PyObject*)self, 0);
}
+static PyObject*
+obj_get_blocksignature(PyObject* self, void* closure __attribute__((__unused__)))
+{
+ if (PyObjCObject_IsBlock(self)) {
+ PyObject* v = (PyObject*)PyObjCObject_GetBlock(self);
+ if (v != NULL) {
+ Py_INCREF(v);
+ return v;
+ }
+ }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static int
+obj_set_blocksignature(PyObject* self, PyObject* newVal, void* closure __attribute__((__unused__)))
+{
+ if (!PyObjCObject_IsBlock(self)) {
+ PyErr_SetString(PyExc_TypeError, "You can only change this value on blocks");
+ return -1;
+ }
+
+ if (newVal != NULL) {
+ if (!PyObjCMethodSignature_Check(newVal)) {
+ PyErr_SetString(PyExc_TypeError, "New value must be a method signature");
+ return -1;
+ }
+ }
+
+ PyObject* v = (PyObject*)PyObjCObject_GetBlock(self);
+ if (v != NULL) {
+ Py_DECREF(v);
+ }
+
+
+ Py_XINCREF(newVal);
+ PyObjCObject_SET_BLOCK(self, (PyObjCMethodSignature*)newVal);
+ return 0;
+}
+
+
static PyGetSetDef obj_getset[] = {
{
"pyobjc_ISA",
@@ -603,6 +651,13 @@
obj_get_instanceMethods_doc,
0
},
+ {
+ "__block_signature__",
+ obj_get_blocksignature,
+ obj_set_blocksignature,
+ "Call signature for a block, or None",
+ 0
+ },
{ 0, 0, 0, 0, 0 }
};
@@ -818,6 +873,10 @@
return NULL;
}
+ if (cls_type->tp_basicsize == sizeof(PyObjCBlockObject)) {
+ flags |= PyObjCObject_kBLOCK;
+ }
+
/* This should be in the tp_alloc for the new class, but
* adding a tp_alloc to PyObjCClass_Type doesn't seem to help
*/
@@ -826,6 +885,10 @@
((PyObjCObject*)res)->objc_object = objc_object;
((PyObjCObject*)res)->flags = flags;
+ if (flags & PyObjCObject_kBLOCK) {
+ ((PyObjCBlockObject*)res)->signature = NULL;
+ }
+
if (retain) {
if (strcmp(object_getClassName(objc_object),
"NSAutoreleasePool") != 0) {
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/objc_support.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/objc_support.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/objc_support.m Mon Jun 1 05:02:14 2009
@@ -387,6 +387,10 @@
case _C_ID:
++type;
+ if (*type == '?') {
+ /* Block pointer */
+ type++;
+ }
if (*type == '"') {
/* embedded field name in an ivar_type */
type=strchr(type+1, '"');
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/parsexml.m
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/parsexml.m (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/parsexml.m Mon Jun 1 05:02:14 2009
@@ -415,8 +415,8 @@
}
if (s) xmlFree(s);
- if (attribute_bool(node, "function_pointer", NULL, NO)) {
- /* Function argument is a function pointer, there are
+ if (attribute_bool(node, "function_pointer", NULL, NO) || attribute_bool(node, "block", NULL, NO)) {
+ /* Function argument is a function pointer or a block, there are
* subelements describing the full type
*/
v = PyBool_FromLong(
@@ -457,6 +457,39 @@
xmlNode* al;
int idx = 0;
+ if (attribute_bool(node, "block", NULL, NO)) {
+ /* Blocks have an implict first argument, include that in the
+ * argument list.
+ */
+ PyObject* a = PyDict_New();
+ if (a == NULL) {
+ Py_DECREF(result);
+ return NULL;
+ }
+ PyObject* av = PyString_FromString("^v");
+ if (av == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(result);
+ return NULL;
+ }
+ PyDict_SetItemString(a, "type", av);
+ Py_DECREF(av);
+
+ av = PyInt_FromLong(idx++);
+ if (av == NULL) {
+ Py_DECREF(a);
+ Py_DECREF(av);
+ Py_DECREF(result);
+ return NULL;
+ }
+ r = PyDict_SetItem(arguments, av, a);
+ Py_DECREF(av); Py_DECREF(a);
+ if (r == -1) {
+ Py_DECREF(result);
+ return NULL;
+ }
+
+ }
for (al = node->children; al != NULL; al = al->next) {
if (al->type != XML_ELEMENT_NODE) {
continue;
Modified: trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h
==============================================================================
--- trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h (original)
+++ trunk/pyobjc/pyobjc-core/Modules/objc/pyobjc.h Mon Jun 1 05:02:14 2009
@@ -96,6 +96,7 @@
#include "registry.h"
#include "corefoundation.h"
#include "closure_pool.h"
+#include "block_support.h"
extern PyObject* PyObjCMethodAccessor_New(PyObject* base, int class_method);
Modified: trunk/pyobjc/pyobjc-core/NEWS.txt
==============================================================================
--- trunk/pyobjc/pyobjc-core/NEWS.txt (original)
+++ trunk/pyobjc/pyobjc-core/NEWS.txt Mon Jun 1 05:02:14 2009
@@ -7,6 +7,24 @@
Version 2.2 (...)
-----------------
+- There is initial support for Objective-C blocks, based on the implementation
+ description in the `clang repository`__. Blocks are represented in Python
+ as callable objects. This means you can pass an arbitrary callable when
+ an Objective-C argument is a block, and that when your method accepts a block
+ it will get passed a callable object.
+
+ There are some limitations on the usage of blocks due to lack of introspection
+ in the current implementation of blocks. This has two side-effects:
+
+ * There must be metadata to describe the signature of blocks in PyObjC's
+ metadata XML files.
+
+ * Block metadata is not retained when a block is stored in an ObjC datastructure,
+ such as an ``NSArray``, and there are no direct references to the block from
+ Python.
+
+.. __: http://llvm.org/svn/llvm-project/cfe/trunk/docs/BlockImplementation.txt
+
- ``objc.inject`` is no longer support. This was code that had no real relation
to the rest of PyObjC and was only working in 32-bit mode with little reason
to expect that it would ever be ported to 64-bit mode.
Modified: trunk/pyobjc/pyobjc-core/setup.py
==============================================================================
--- trunk/pyobjc/pyobjc-core/setup.py (original)
+++ trunk/pyobjc/pyobjc-core/setup.py Mon Jun 1 05:02:14 2009
@@ -7,6 +7,7 @@
import os
import glob
import site
+import platform
if 'MallocStackLogging' in os.environ:
del os.environ['MallocStackLogging']
@@ -145,7 +146,7 @@
# The following flags are an attempt at getting rid of /usr/local
# in the compiler search path.
"-DPyObjC_STRICT_DEBUGGING",
- "-DMACOSX",
+ "-DPyObjC_BUILD_RELEASE=%02d%02d"%(tuple(map(int, platform.mac_ver()[0].split('.')[:2]))),
"-no-cpp-precomp",
#"-Wno-long-double",
#"-Wselector",
------------------------------------------------------------------------------
Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT
is a gathering of tech-side developers & brand creativity professionals. Meet
the minds behind Google Creative Lab, Visual Complexity, Processing, &
iPhoneDevCamp as they present alongside digital heavyweights like Barbarian
Group, R/GA, & Big Spaceship. http://p.sf.net/sfu/creativitycat-com