From bd40a83f1ca1c499577874865c764317fb094435 Mon Sep 17 00:00:00 2001 From: Mark Rose Date: Thu, 6 Mar 2003 19:21:58 +0000 Subject: [PATCH] polymorphism patch merge git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@4435 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- SWIG/CHANGES.current | 18 + SWIG/Lib/python/director.swg | 183 +++++++ SWIG/Lib/python/python.swg | 125 +++++ SWIG/Lib/python/std_complex.i | 41 ++ SWIG/Lib/python/std_string.i | 21 + SWIG/Lib/python/std_vector.i | 182 +++++++ SWIG/Source/Include/swigwarn.h | 3 + SWIG/Source/Modules/lang.cxx | 304 ++++++++++- SWIG/Source/Modules/main.cxx | 19 + SWIG/Source/Modules/python.cxx | 902 ++++++++++++++++++++++++++++++++- SWIG/Source/Modules/swigmod.h | 36 +- SWIG/Source/Swig/cwrap.c | 118 ++++- SWIG/Source/Swig/naming.c | 34 ++ SWIG/Source/Swig/stype.c | 26 + SWIG/Source/Swig/swig.h | 10 + 15 files changed, 2007 insertions(+), 15 deletions(-) create mode 100644 SWIG/Lib/python/director.swg diff --git a/SWIG/CHANGES.current b/SWIG/CHANGES.current index 7b81ab7ac..566bed151 100644 --- a/SWIG/CHANGES.current +++ b/SWIG/CHANGES.current @@ -1,6 +1,24 @@ Version 1.3.18 (In progress) ============================ +03/06/2003: mrose (Mark Rose) + Merged the cross-language polymorphism patch. When enabled, C++ + "proxy" classes (called directors) for each specified C++ class. + Directors pass method calls from C++ to Python, similar to the way + the usual proxy (shadow) classes pass method calls from Python to + C++. Together, these two types of proxies allow C++ classes that + are extended in Python to behave just like ordinary C++ classes and + be used in C++ like native objects. + + This feature is still very experimental and is disabled by default. + To enable director support, specify '-fdirectors' on the SWIG command + line or in the SWIG_FEATURES environment variable. In the interface + file, add %feature("director") to generate directors for all classes + that have virtual methods. + + See http://stm.lbl.gov/~tm2/swig/ProxyDoc.html for more details. + + 03/03/2003: beazley Fixed a small glitch in typemap local variable replacement. If you had a typemap like this: diff --git a/SWIG/Lib/python/director.swg b/SWIG/Lib/python/director.swg new file mode 100644 index 000000000..70097f17f --- /dev/null +++ b/SWIG/Lib/python/director.swg @@ -0,0 +1,183 @@ +/*********************************************************************** + * director.swg + * + * This file contains support for director classes that proxy + * method calls from C++ to Python extensions. + * + * Author : Mark Rose (mrose@stm.lbl.gov) + ************************************************************************/ + +%insert(runtime) %{ + +#ifdef __cplusplus + +#include + +/* base class for director exceptions */ +class SWIG_DIRECTOR_EXCEPTION { +protected: + std::string _msg; +public: + SWIG_DIRECTOR_EXCEPTION(const char* msg="") { + } + const char *getMessage() { return _msg.c_str(); } + virtual ~SWIG_DIRECTOR_EXCEPTION() { } +}; + +/* type mismatch in the return value from a python method call */ +class SWIG_DIRECTOR_TYPE_MISMATCH: public SWIG_DIRECTOR_EXCEPTION { +public: + SWIG_DIRECTOR_TYPE_MISMATCH(const char* msg="") { + _msg = "Swig director type mismatch: "; + _msg += msg; + PyErr_SetString(PyExc_TypeError, msg); + } +}; + +/* any python exception that occurs during a director method call */ +class SWIG_DIRECTOR_METHOD_EXCEPTION: public SWIG_DIRECTOR_EXCEPTION { }; + +/* simple thread abstraction for pthreads or win32 */ +#ifdef __THREAD__ + #define __PTHREAD__ + #if defined(_WIN32) || defined(__WIN32__) + #define pthread_mutex_lock EnterCriticalSection + #define pthread_mutex_unlock LeaveCriticalSection + #define pthread_mutex_t CRITICAL_SECTION + #define MUTEX_INIT(var) CRITICAL_SECTION var + #else + #include + #define MUTEX_INIT(var) pthread_mutex_t var = PTHREAD_MUTEX_INITIALIZER + #endif +#endif + +/* director base class */ +class __DIRECTOR__ { +private: + /* pointer to the wrapped python object */ + PyObject* _self; + /* flag indicating whether the object is owned by python or c++ */ + mutable int _disown; + /* shared flag for breaking recursive director calls */ + static int _up; + +#ifdef __PTHREAD__ + /* locks for sharing the _up flag in a threaded environment */ + static pthread_mutex_t _mutex_up; + static int _mutex_active; + static pthread_t _mutex_thread; +#endif + + /* decrement the reference count of the wrapped python object */ + void __decref() const { + assert(_self); + if (_disown) { + Py_DECREF(_self); + } + } + + /* reset the _up flag once the routing direction has been determined */ +#ifdef __PTHREAD__ + void __clear_up() const { + __DIRECTOR__::_up = 0; + __DIRECTOR__::_mutex_active = 0; + pthread_mutex_unlock(&_mutex_up); + } +#else + void __clear_up() const { + __DIRECTOR__::_up = 0; + } +#endif + +public: + /* the default constructor should not be called */ + __DIRECTOR__() { + assert(0); + } + + /* wrap a python object, optionally taking ownership */ + __DIRECTOR__(PyObject* self, int disown): _self(self), _disown(disown) { + __incref(); + } + + /* discard our reference at destruction */ + virtual ~__DIRECTOR__() { + __decref(); + } + + /* return a pointer to the wrapped python object */ + PyObject *__get_self() const { + return _self; + } + + + /* get the _up flag to determine if the method call should be routed + * to the c++ base class or through the wrapped python object + */ +#ifdef __PTHREAD__ + int __get_up() const { + if (__DIRECTOR__::_mutex_active) { + if (pthread_equal(__DIRECTOR__::_mutex_thread, pthread_self())) { + int up = _up; + __clear_up(); + return up; + } + } + return 0; + } +#else + int __get_up() const { + int up = _up; + _up = 0; + return up; + } +#endif + + /* set the _up flag if the next method call should be directed to + * the c++ base class rather than the wrapped python object + */ +#ifdef __PTHREAD__ + void __set_up() const { + pthread_mutex_lock(&__DIRECTOR__::_mutex_up); + __DIRECTOR__::_mutex_thread = pthread_self(); + __DIRECTOR__::_mutex_active = 1; + __DIRECTOR__::_up = 1; + } +#else + void __set_up() const { + __DIRECTOR__::_up = 1; + } +#endif + + /* acquire ownership of the wrapped python object (the sense of "disown" + * is from python) */ + void __disown() const { + assert(_self); + if (!_disown) { + _disown=1; + __incref(); + } + } + + /* increase the reference count of the wrapped python object */ + void __incref() const { + assert(_self); + if (_disown) { + Py_INCREF(_self); + } + } + +}; + +int __DIRECTOR__::_up = 0; + +#ifdef __PTHREAD__ + MUTEX_INIT(__DIRECTOR__::_mutex_up); + pthread_t __DIRECTOR__::_mutex_thread; + int __DIRECTOR__::_mutex_active = 0; +#endif + +#endif /* __cplusplus */ + +%} + diff --git a/SWIG/Lib/python/python.swg b/SWIG/Lib/python/python.swg index 5ef406ac9..fb852d00f 100644 --- a/SWIG/Lib/python/python.swg +++ b/SWIG/Lib/python/python.swg @@ -22,6 +22,126 @@ * standard typemaps * ----------------------------------------------------------------------------- */ + +/***************************************************************************** + * + * Inverse argument typemaps are for marshaling C/C++ parameters to call Python + * methods from C++ proxy wrapper classes. + * + *****************************************************************************/ + +/* --- Inverse arguments --- */ + +/* Primitive datatypes. These only supply a parse code to PyObject_CallMethod */ + +%typemap(inv,parse="i") int ""; +%typemap(inv,parse="h") short ""; +%typemap(inv,parse="l") long ""; +%typemap(inv,parse="b") signed char ""; +%typemap(inv,parse="f") float ""; +%typemap(inv,parse="d") double ""; +%typemap(inv,parse="s") char* ""; +%typemap(inv,parse="i") bool ""; + +%typemap(inv,parse="l") unsigned int, unsigned short, unsigned long, unsigned char "(long) $1_name"; + +%typemap(inv) long long + "$input = PyLong_FromLongLong($1_name);"; +%typemap(inv) unsigned long long + "$input = PyLong_FromUnsignedLongLong($1_name);"; + +%typemap(inv, parse="l") int *INV, long* INV, + unsigned int *INV, unsigned long *INV, + short *INV, unsigned short *INV, + char *INV, unsigned char *INV + "(long) *$1_name"; +%typemap(inv, parse="f") float *INV "*$1_name"; +%typemap(inv, parse="d") double *INV "*$1_name"; + +%typemap(inv, parse="O") PyObject* ""; + +/* +%typemap(inv, parse="s") SWIGTYPE { +{ + $&1_ltype resultptr; + resultptr = new $1_ltype(($1_ltype &) $1); + $result = SWIG_NewPointerObj((void *) resultptr, $&1_descriptor, 1); +} +} +*/ + +/* no can do... see python.cxx +%typemap(inv) DIRECTORTYPE * { + { + __DIRECTOR__$1_ltype proxy = dynamic_cast<__DIRECTOR__$1_ltype>($1_name); + if (!proxy) { + $input = SWIG_NewPointerObj((void *) $1_name, $1_descriptor, 0); + } else { + $input = proxy->__get_self(); + } + assert($input); + } +} +%typemap(inv) SWIGTYPE * { + $input = SWIG_NewPointerObj((void *) $1_name, $1_descriptor, 0); +} +*/ + +/* +%typemap(inv, parse="s") void "0"; +*/ +/* +%typemap(inv) SWIGTYPE *, SWIGTYPE &, SWIGTYPE [] { + $input = SWIG_NewPointerObj((void *) $1_name, $1_descriptor, $owner); +} +*/ + + +/* --- Outverse arguments --- */ + +%define OUTV_TYPEMAP(type, converter) +%typemap(argoutv) type *OUTV + "*$result = (type) converter($input); + if (PyErr_Occurred()) throw SWIG_DIRECTOR_TYPE_MISMATCH(\"Error converting Python object using converter\");"; +%typemap(outv) type + "$result = (type) converter($input); + if (PyErr_Occurred()) throw SWIG_DIRECTOR_TYPE_MISMATCH(\"Error converting Python object using converter\");"; +%typemap(outv) type &OUTV = type +%enddef + +OUTV_TYPEMAP(char, PyInt_AsLong); +OUTV_TYPEMAP(unsigned char, PyInt_AsLong); +OUTV_TYPEMAP(short, PyInt_AsLong); +OUTV_TYPEMAP(unsigned short, PyInt_AsLong); +OUTV_TYPEMAP(int, PyInt_AsLong); +OUTV_TYPEMAP(unsigned int, PyInt_AsLong); +OUTV_TYPEMAP(long, PyInt_AsLong); +OUTV_TYPEMAP(unsigned long, PyInt_AsLong); +OUTV_TYPEMAP(long long, PyLong_AsLongLong); +OUTV_TYPEMAP(unsigned long long, PyLong_AsUnsignedLongLong); +OUTV_TYPEMAP(float, PyFloat_AsDouble); +OUTV_TYPEMAP(double, PyFloat_AsDouble); +OUTV_TYPEMAP(bool, PyInt_AsLong); +OUTV_TYPEMAP(PyObject *, ); +OUTV_TYPEMAP(char *, PyString_AsString); + + +%typemap(outv) SWIGTYPE *, + SWIGTYPE &, + SWIGTYPE [] + "if ((SWIG_ConvertPtr($input,(void **) &$result, $descriptor,SWIG_POINTER_EXCEPTION | $disown )) == -1) throw SWIG_DIRECTOR_TYPE_MISMATCH(\"Pointer conversion failed.\");"; + +%typemap(outv) void * "if ((SWIG_ConvertPtr($input,(void **) &$result, 0, SWIG_POINTER_EXCEPTION | $disown )) == -1) throw SWIG_DIRECTOR_TYPE_MISMATCH(\"Pointer conversion failed.\");"; + + + +/***************************************************************************** + * + * End of C++ proxy wrapper typemaps. + * + *****************************************************************************/ + + /* --- Input arguments --- */ /* Primitive datatypes. These only supply a parse code to PyTuple_ParseArgs */ @@ -495,6 +615,11 @@ } } +%typecheck(SWIG_TYPECHECK_POINTER) PyObject * +{ + $1 = ($input != 0); +} + /* ------------------------------------------------------------ * Exception handling * ------------------------------------------------------------ */ diff --git a/SWIG/Lib/python/std_complex.i b/SWIG/Lib/python/std_complex.i index 2a4dd489a..dc4920735 100644 --- a/SWIG/Lib/python/std_complex.i +++ b/SWIG/Lib/python/std_complex.i @@ -64,6 +64,47 @@ SwigComplex_AsComplexDouble(PyObject *o) %typemap(out) const Complex & { $result = PyComplex_FromDoubles($1->real(), $1->imag()); } + + // C++ proxy class typemaps + + %typemap(inv) complex { + $input = PyComplex_FromDoubles($1_name.real(), $1_name.imag()); + } + + %typemap(inv) const complex & { + $inupt = PyComplex_FromDoubles($1_name->real(), $1_name->imag()); + } + + %typemap(outv) complex { + if (PyComplex_Check($input)) { + $result = std::complex(PyComplex_RealAsDouble($input), + PyComplex_ImagAsDouble($input)); + } else if (PyFloat_Check($input)) { + $result = std::complex(PyFloat_AsDouble($input), 0); + } else if (PyInt_Check($input)) { + $result = std::complex(PyInt_AsLong($input), 0); + } + else { + throw SWIG_DIRECTOR_TYPE_MISMATCH("Expected a complex"); + } + } + + %typemap(outv) const complex& (std::complex temp) { + if (PyComplex_Check($input)) { + temp = std::complex(PyComplex_RealAsDouble($input), + PyComplex_ImagAsDouble($input)); + $result = &temp; + } else if (PyFloat_Check($input)) { + temp = std::complex(PyFloat_AsDouble($input), 0); + $result = &temp; + } else if (PyInt_Check($input)) { + temp = std::complex(PyInt_AsLong($input), 0); + $result = &temp; + } else { + throw SWIG_DIRECTOR_TYPE_MISMATCH("Expected a complex"); + } + } + %enddef diff --git a/SWIG/Lib/python/std_string.i b/SWIG/Lib/python/std_string.i index 30d1afb7d..6bb5fa52b 100644 --- a/SWIG/Lib/python/std_string.i +++ b/SWIG/Lib/python/std_string.i @@ -50,5 +50,26 @@ namespace std { %typemap(out) const string & { $result = PyString_FromStringAndSize($1->data(),$1->size()); } + + %typemap(inv, parse="s") string, const string &, string & "$1_name.c_str()"; + + %typemap(inv, parse="s") string *, const string * "$1_name->c_str()"; + + %typemap(outv) string { + if (PyString_Check($input)) + $result = std::string(PyString_AsString($input)); + else + throw SWIG_DIRECTOR_TYPE_MISMATCH("string expected"); + } + + %typemap(outv) const string & (std::string temp) { + if (PyString_Check($input)) { + temp = std::string(PyString_AsString($input)); + $result = &temp; + } else { + throw SWIG_DIRECTOR_TYPE_MISMATCH("string expected"); + } + } + } diff --git a/SWIG/Lib/python/std_vector.i b/SWIG/Lib/python/std_vector.i index 83de1de5a..fb40c0255 100644 --- a/SWIG/Lib/python/std_vector.i +++ b/SWIG/Lib/python/std_vector.i @@ -106,6 +106,31 @@ namespace std { SWIG_fail; } } + %typemap(outv) vector (std::vector* v) { + if (PyTuple_Check($input) || PyList_Check($input)) { + unsigned int size = (PyTuple_Check($input) ? + PyTuple_Size($input) : + PyList_Size($input)); + $result = std::vector(size); + for (unsigned int i=0; i expected"); + } + } + } else if (SWIG_ConvertPtr($input,(void **) &v, + $&descriptor,1) != -1){ + $result = *v; + } else { + throw SWIG_DIRECTOR_TYPE_MISMATCH("vector<" #T "> expected"); + } + } %typemap(in) const vector& (std::vector temp, std::vector* v), const vector* (std::vector temp, @@ -138,6 +163,35 @@ namespace std { SWIG_fail; } } + %typemap(outv) const vector& (std::vector temp, + std::vector* v), + const vector* (std::vector temp, + std::vector* v) { + if (PyTuple_Check($input) || PyList_Check($input)) { + unsigned int size = (PyTuple_Check($input) ? + PyTuple_Size($input) : + PyList_Size($input)); + temp = std::vector(size); + $result = &temp; + for (unsigned int i=0; i expected"); + } + } + } else if (SWIG_ConvertPtr($input,(void **) &v, + $descriptor,1) != -1){ + $result = v; + } else { + throw SWIG_DIRECTOR_TYPE_MISMATCH("vector<" #T "> expected"); + } + } %typemap(out) vector { $result = PyTuple_New($1.size()); for (unsigned int i=0; i<$1.size(); i++) { @@ -147,6 +201,15 @@ namespace std { $descriptor(T *), 1)); } } + %typemap(inv) vector { + $input = PyTuple_New($1.size()); + for (unsigned int i=0; i<$1.size(); i++) { + T* ptr = new T((($1_type &)$1)[i]); + PyTuple_SetItem($input,i, + SWIG_NewPointerObj((void *) ptr, + $descriptor(T *), 1)); + } + } %typecheck(SWIG_TYPECHECK_VECTOR) vector { /* native sequence? */ if (PyTuple_Check($input) || PyList_Check($input)) { @@ -323,6 +386,31 @@ namespace std { SWIG_fail; } } + %typemap(outv) vector (std::vector* v) { + if (PyTuple_Check($input) || PyList_Check($input)) { + unsigned int size = (PyTuple_Check($input) ? + PyTuple_Size($input) : + PyList_Size($input)); + $result = std::vector(size); + for (unsigned int i=0; i expected"); + } + } + } else if (SWIG_ConvertPtr($input,(void **) &v, + $&descriptor,1) != -1){ + $result = *v; + } else { + throw SWIG_DIRECTOR_TYPE_MISMATCH("vector<" #T "> expected"); + } + } %typemap(in) const vector& (std::vector temp, std::vector* v), const vector* (std::vector temp, @@ -355,6 +443,35 @@ namespace std { SWIG_fail; } } + %typemap(outv) const vector& (std::vector temp, + std::vector* v), + const vector* (std::vector temp, + std::vector* v) { + if (PyTuple_Check($input) || PyList_Check($input)) { + unsigned int size = (PyTuple_Check($input) ? + PyTuple_Size($input) : + PyList_Size($input)); + temp = std::vector(size); + $result = &temp; + for (unsigned int i=0; i expected"); + } + } + } else if (SWIG_ConvertPtr($input,(void **) &v, + $descriptor,1) != -1){ + $result = v; + } else { + throw SWIG_DIRECTOR_TYPE_MISMATCH("vector<" #T "> expected"); + } + } %typemap(out) vector { $result = PyTuple_New($1.size()); for (unsigned int i=0; i<$1.size(); i++) { @@ -364,6 +481,15 @@ namespace std { $descriptor(T), 0)); } } + %typemap(inv) vector { + $input = PyTuple_New($1_name.size()); + for (unsigned int i=0; i<$1_name.size(); i++) { + T ptr = (($1_type &)$1)[i]; + PyTuple_SetItem($input,i, + SWIG_NewPointerObj((void *) ptr, + $descriptor(T), 0)); + } + } %typecheck(SWIG_TYPECHECK_VECTOR) vector { /* native sequence? */ if (PyTuple_Check($input) || PyList_Check($input)) { @@ -537,6 +663,29 @@ namespace std { SWIG_fail; } } + %typemap(outv) vector (std::vector* v) { + if (PyTuple_Check($input) || PyList_Check($input)) { + unsigned int size = (PyTuple_Check($input) ? + PyTuple_Size($input) : + PyList_Size($input)); + $result = std::vector(size); + for (unsigned int i=0; i expected"); + } + } + } else if (SWIG_ConvertPtr($input,(void **) &v, + $&descriptor,1) != -1){ + $result = *v; + } else { + throw SWIG_DIRECTOR_TYPE_MISMATCH("vector<" #T "> expected"); + } + } %typemap(in) const vector& (std::vector temp, std::vector* v), const vector* (std::vector temp, @@ -567,12 +716,45 @@ namespace std { SWIG_fail; } } + %typemap(outv) const vector& (std::vector temp, + std::vector* v), + const vector* (std::vector temp, + std::vector* v) { + if (PyTuple_Check($input) || PyList_Check($input)) { + unsigned int size = (PyTuple_Check($input) ? + PyTuple_Size($input) : + PyList_Size($input)); + temp = std::vector(size); + $result = &temp; + for (unsigned int i=0; i expected"); + } + } + } else if (SWIG_ConvertPtr($input,(void **) &v, + $descriptor,1) != -1){ + $result = v; + } else { + throw SWIG_DIRECTOR_TYPE_MISMATCH("vector<" #T "> expected"); + } + } %typemap(out) vector { $result = PyTuple_New($1.size()); for (unsigned int i=0; i<$1.size(); i++) PyTuple_SetItem($result,i, CONVERT_TO((($1_type &)$1)[i])); } + %typemap(inv) vector { + $input = PyTuple_New($1_name.size()); + for (unsigned int i=0; i<$1_name.size(); i++) + PyTuple_SetItem($input,i, + CONVERT_TO((($1_type &)$1_name)[i])); + } %typecheck(SWIG_TYPECHECK_VECTOR) vector { /* native sequence? */ if (PyTuple_Check($input) || PyList_Check($input)) { diff --git a/SWIG/Source/Include/swigwarn.h b/SWIG/Source/Include/swigwarn.h index 90a79c917..cb3e02a87 100644 --- a/SWIG/Source/Include/swigwarn.h +++ b/SWIG/Source/Include/swigwarn.h @@ -140,6 +140,7 @@ #define WARN_TYPEMAP_VAR_UNDEF 466 #define WARN_TYPEMAP_TYPECHECK 467 #define WARN_TYPEMAP_THROW 468 +#define WARN_TYPEMAP_INV_UNDEF 469 /* -- General code generation -- */ @@ -156,6 +157,8 @@ #define WARN_LANG_OVERLOAD_KEYWORD 511 #define WARN_LANG_OVERLOAD_CONST 512 #define WARN_LANG_CLASS_UNNAMED 513 +#define WARN_LANG_DIRECTOR_VDESTRUCT 514 +#define WARN_LANG_DISCARD_CONST 515 /* -- Reserved (600-799) -- */ diff --git a/SWIG/Source/Modules/lang.cxx b/SWIG/Source/Modules/lang.cxx index e5177de95..be0a24d7f 100644 --- a/SWIG/Source/Modules/lang.cxx +++ b/SWIG/Source/Modules/lang.cxx @@ -203,6 +203,7 @@ Language::Language() { classtypes = NewHash(); overloading = 0; multiinput = 0; + directors = 0; } Language::~Language() { @@ -1292,6 +1293,265 @@ int Language::typedefHandler(Node *) { return SWIG_OK; } +/* ---------------------------------------------------------------------- + * Language::classDirectorMethod() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorMethod(Node *n, Node *parent, String* super) { + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorConstructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorConstructor(Node *n) { + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorDefaultConstructor() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDefaultConstructor(Node *n) { + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::tagDirectorBases() + * ---------------------------------------------------------------------- */ + +int Language::tagDirectorBases(Node *n) { + List* bl; + if (Getattr(n, "directorBase")) return SWIG_OK; + if (Getattr(n, "hasVirtual") == 0) return SWIG_OK; + Setattr(n, "directorBase", "1"); + bl = Getattr(n, "bases"); + if (bl) { + Node* bi; + for (bi = Firstitem(bl); bi; bi = Nextitem(bl)) { + tagDirectorBases(bi); + } + } + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::unrollVirtualMethods() + * ---------------------------------------------------------------------- */ + +int Language::unrollVirtualMethods(Node *n, + Node *parent, + Hash *vm, + int default_director, + int &virtual_destructor, + int &has_virtual) { + int only_virtual = (Getattr(parent, "director:nonvirtual") == 0); + int top = (n == parent); + has_virtual = 0; + Node *ni; + String *type; + String *nodeType; + String *cdecl; + String *storage; + String *classname; + String *decl; + // default_director < 0 turns off director generation for this class and all its superclasses + if (default_director >= 0) { + if (Getattr(n, "feature:director")) default_director = 1; + if (Getattr(n, "feature:nodirector")) default_director = -1; + } + classname = Getattr(n, "name"); + for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + nodeType = Getattr(ni, "nodeType"); + storage = Getattr(ni, "storage"); + cdecl = Getattr(ni, "cdecl"); + decl = Getattr(ni, "decl"); + if (!Cmp(nodeType, "cdecl") && SwigType_isfunction(decl)) { + int is_virtual = storage && !Cmp(storage, "virtual"); + if (is_virtual) has_virtual = 1; + String* access = Getattr(ni, "access"); + if (!access || !Cmp(access, "public")) { + if (!only_virtual || is_virtual) { + String *method_id; + String *name = Getattr(ni, "name"); + method_id = NewStringf("%s|%s", name, decl); + int director = default_director; + if (director >= 0) { + if (Getattr(ni, "feature:director")) director = 1; + if (Getattr(ni, "feature:nodirector")) director = 0; + } + if ((director == 1) && !Getattr(vm, method_id)) { + String *fqname = NewString(""); + Printf(fqname, "%s::%s", classname, name); + Hash *item = NewHash(); + Setattr(item, "fqName", fqname); + Setattr(item, "methodNode", ni); + Setattr(vm, method_id, item); + Delete(fqname); + Delete(item); + } + Delete(method_id); + } + } + } + else if (!Cmp(nodeType, "destructor")) { + if (storage && !Cmp(storage, "virtual")) { + virtual_destructor = 1; + } + } + else { + } + } + List* bl = Getattr(n, "bases"); + if (bl) { + Node* bi; + for (bi = Firstitem(bl); bi; bi = Nextitem(bl)) { + int virtual_base = 0; + unrollVirtualMethods(bi, parent, vm, default_director, virtual_destructor, virtual_base); + if (virtual_base) { + has_virtual = 1; + } + } + } + if (has_virtual) { + Setattr(n, "hasVirtual", "1"); + } + return SWIG_OK; +} + + +/* ---------------------------------------------------------------------- + * Language::classDirectorDisown() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorDisown(Node *n) { + Node *disown = NewHash(); + String *mrename; + String *symname = Getattr(n,"sym:name"); + mrename = Swig_name_disown(symname); //Getattr(n, "name")); + String *type = NewString(ClassType); + String *name = NewString("self"); + SwigType_add_pointer(type); + Parm *p = NewParm(type, name); + Delete(name); + Delete(type); + type = NewString("void"); + String *action = NewString(""); + Printv(action, "{\n", + "__DIRECTOR__ *director = dynamic_cast<__DIRECTOR__*>(arg1);\n", + "if (director) director->__disown();\n", + "}\n", + NULL); + Setattr(disown, "wrap:action", action); + Setattr(disown,"name", mrename); + Setattr(disown,"sym:name", mrename); + Setattr(disown,"type",type); + Setattr(disown,"parms", p); + Delete(action); + Delete(mrename); + Delete(type); + Delete(p); + + functionWrapper(disown); + Delete(disown); + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorConstructors() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorConstructors(Node *n) { + Node *ni; + String *nodeType; + int constructor = 0; + for (ni = Getattr(n, "firstChild"); ni; ni = nextSibling(ni)) { + nodeType = Getattr(ni, "nodeType"); + if (!Cmp(nodeType, "constructor")) { + classDirectorConstructor(ni); + constructor = 1; + } + } + if (!constructor) { + classDirectorDefaultConstructor(n); + } +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorMethods() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorMethods(Node *n) { + Node *vtable = Getattr(n, "vtable"); + Node *item; + String *key; + for (key = Firstkey(vtable); key != 0; key = Nextkey(vtable)) { + item = Getattr(vtable, key); + String *method = Getattr(item, "methodNode"); + String *fqname = Getattr(item, "fqName"); + if (classDirectorMethod(method, n, fqname) == SWIG_OK) { + Setattr(item, "director", "1"); + } + } +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorInit() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorInit(Node *n) { + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirectorEnd() + * ---------------------------------------------------------------------- */ + +int Language::classDirectorEnd(Node *n) { + return SWIG_OK; +} + +/* ---------------------------------------------------------------------- + * Language::classDirector() + * ---------------------------------------------------------------------- */ + +int Language::classDirector(Node *n) { + Node *module = Getattr(n,"module"); + String *classtype = Getattr(n, "classtype"); + Hash *directormap = 0; + if (module) { + directormap = Getattr(module, "wrap:directormap"); + if (directormap == 0) { + directormap = NewHash(); + Setattr(module, "wrap:directormap", directormap); + } + } + Hash* vtable = NewHash(); + int virtual_destructor = 0; + int has_virtual = 0; + unrollVirtualMethods(n, n, vtable, 0, virtual_destructor, has_virtual); + if (Len(vtable) > 0) { + if (!virtual_destructor) { + String *classtype = Getattr(n, "classtype"); + Swig_warning(WARN_LANG_DIRECTOR_VDESTRUCT, input_file, line_number, + "Director base class %s has no virtual destructor.\n", + classtype); + } + Setattr(n, "vtable", vtable); + tagDirectorBases(n); + classDirectorInit(n); + classDirectorConstructors(n); + classDirectorMethods(n); + classDirectorEnd(n); + if (directormap != 0) { + Setattr(directormap, classtype, n); + } + } + Delete(vtable); + return SWIG_OK; +} + /* ---------------------------------------------------------------------- * Language::classDeclaration() * ---------------------------------------------------------------------- */ @@ -1339,6 +1599,12 @@ int Language::classDeclaration(Node *n) { } Setattr(n,"classtype", SwigType_namestr(ClassType)); +/* + if (CPlusPlus) { + classDirector(n); + } +*/ + InClass = 1; CurrentClass = n; @@ -1349,10 +1615,14 @@ int Language::classDeclaration(Node *n) { } /* Call classHandler() here */ - if (!ImportMode) + if (!ImportMode) { + if (CPlusPlus && directorsEnabled()) { + classDirector(n); + } classHandler(n); - else + } else { Language::classHandler(n); + } InClass = 0; CurrentClass = 0; @@ -1399,6 +1669,12 @@ int Language::classHandler(Node *n) { destructorHandler(CurrentClass); } } + + /* emit director disown method */ + if (Getattr(n, "vtable")) { + classDirectorDisown(n); + } + return SWIG_OK; } @@ -1816,6 +2092,30 @@ void Language::allow_multiple_input(int val) { multiinput = val; } +/* ----------------------------------------------------------------------------- + * Language::allow_directors() + * ----------------------------------------------------------------------------- */ + +void Language::allow_directors(int val) { + directors = val; +} + +/* ----------------------------------------------------------------------------- + * Language::directorsEnabled() + * ----------------------------------------------------------------------------- */ + +int Language::directorsEnabled() const { + return directors; +} + +/* ----------------------------------------------------------------------------- + * Language::is_smart_pointer() + * ----------------------------------------------------------------------------- */ + +int Language::is_smart_pointer() const { + return SmartPointer; +} + /* ----------------------------------------------------------------------------- * Language::is_wrapping_class() * ----------------------------------------------------------------------------- */ diff --git a/SWIG/Source/Modules/main.cxx b/SWIG/Source/Modules/main.cxx index 8626a7724..c36810952 100644 --- a/SWIG/Source/Modules/main.cxx +++ b/SWIG/Source/Modules/main.cxx @@ -72,6 +72,7 @@ static char *usage = (char*)"\ -swiglib - Report location of SWIG library and exit\n\ -v - Run in verbose mode\n\ -fcompact - Compile in compact mode\n\ + -fdirectors - Enable C++ directors\n\ -fvirtual - Compile in virtual elimination mode\n\ -small - Compile in virtual elimination & compact mode\n\ -version - Print SWIG version number\n\ @@ -189,6 +190,7 @@ int SWIG_main(int argc, char *argv[], Language *l) { int dump_classes = 0; int werror = 0; int depend = 0; + int directors = 0; DOH *libfiles = 0; DOH *cpps = 0 ; @@ -285,6 +287,9 @@ int SWIG_main(int argc, char *argv[], Language *l) { } else if (strcmp(temp, "-small") == 0) { Wrapper_compact_print_mode_set(1); Wrapper_virtual_elimination_mode_set(1); + } else if (strcmp(temp, "-fdirectors") == 0) { + directors = 1; + lang->allow_directors(); } } } @@ -324,6 +329,10 @@ int SWIG_main(int argc, char *argv[], Language *l) { Wrapper_compact_print_mode_set(1); Wrapper_virtual_elimination_mode_set(1); Swig_mark_arg(i); + } else if (strcmp(argv[i], "-fdirectors") == 0) { + directors = 1; + lang->allow_directors(); + Swig_mark_arg(i); } else if (strcmp(argv[i],"-c") == 0) { NoInclude=1; Preprocessor_define((DOH *) "SWIG_NOINCLUDE 1", 0); @@ -534,6 +543,9 @@ int SWIG_main(int argc, char *argv[], Language *l) { if (lang_config) { Printf(fs,"\n%%include \"%s\"\n", lang_config); } + if (directors) { + Printf(fs,"\n%%include \"director.swg\"\n"); + } Printf(fs,"%%include \"%s\"\n", Swig_last_file()); for (i = 0; i < Len(libfiles); i++) { Printf(fs,"\n%%include \"%s\"\n", Getitem(libfiles,i)); @@ -631,8 +643,15 @@ int SWIG_main(int argc, char *argv[], Language *l) { } else { Setattr(top,"outfile", NewStringf("%s_wrap.c", Swig_file_basename(input_file))); } + Setattr(top,"outfile_h", NewStringf("%s_wrap.h", Swig_file_basename(input_file))); } else { + char *header = strdup(outfile_name); + char *ext = header + strlen(header); + while (ext > header && *ext != '.') ext--; + if (*ext == '.') *ext = 0; Setattr(top,"outfile", outfile_name); + Setattr(top,"outfile_h", NewStringf("%s.h", header)); + free(header); } if (contracts) { Swig_contracts(top); diff --git a/SWIG/Source/Modules/python.cxx b/SWIG/Source/Modules/python.cxx index 6651ace92..ec7cbd9d9 100644 --- a/SWIG/Source/Modules/python.cxx +++ b/SWIG/Source/Modules/python.cxx @@ -19,6 +19,255 @@ char cvsroot_python_cxx[] = "$Header$"; #include + +/********************************************************************************** + * + * TYPE UTILITY FUNCTIONS + * + * These ultimately belong elsewhere, but for now I'm leaving them here to + * make it easier to keep an eye on them during testing. Not all of these may + * be necessary, and some may duplicate existing functionality in SWIG. --MR + * + **********************************************************************************/ + +/* Swig_csuperclass_call() + * + * Generates a fully qualified method call, including the full parameter list. + * e.g. "base::method(i, j)" + * + */ + +String *Swig_csuperclass_call(String* base, String* method, ParmList* l) { + String *call = NewString(""); + Parm *p; + if (base) { + Printf(call, "%s::", base); + } + Printf(call, "%s(", method); + for (p=l; p; p = nextSibling(p)) { + String *pname = Getattr(p, "name"); + if (p != l) Printf(call, ", "); + Printv(call, pname, NIL); + } + Printf(call, ")"); + return call; +} + +/* Swig_class_declaration() + * + * Generate the start of a class/struct declaration. + * e.g. "class myclass" + * + */ + +String *Swig_class_declaration(Node *n, String *name) { + if (!name) { + name = Getattr(n, "sym:name"); + } + String *result = NewString(""); + String *kind = Getattr(n, "kind"); + Printf(result, "%s %s", kind, name); + return result; +} + +String *Swig_class_name(Node *n) { + String *name; + name = Copy(Getattr(n, "sym:name")); + return name; +} + +/* Swig_director_declaration() + * + * Generate the full director class declaration, complete with base classes. + * e.g. "class __DIRECTOR__myclass: public myclass, public __DIRECTOR__ {" + * + */ + +String *Swig_director_declaration(Node *n) { + String* classname = Swig_class_name(n); + String *directorname = NewStringf("__DIRECTOR__%s", classname); + String *base = Getattr(n, "classtype"); + String *declaration = Swig_class_declaration(n, directorname); + Printf(declaration, ": public %s, public __DIRECTOR__ {\n", base); + Delete(classname); + Delete(directorname); + return declaration; +} + + +String * +Swig_method_call(String_or_char *name, ParmList *parms) { + String *func; + int i = 0; + int comma = 0; + Parm *p = parms; + SwigType *pt; + String *nname; + + func = NewString(""); + nname = SwigType_namestr(name); + Printf(func,"%s(", nname); + while (p) { + String *pname; + pt = Getattr(p,"type"); + if ((SwigType_type(pt) != T_VOID)) { + if (comma) Printf(func,","); + pname = Getattr(p, "name"); + Printf(func,"%s", pname); + comma = 1; + i++; + } + p = nextSibling(p); + } + Printf(func,")"); + return func; +} + +/* method_decl + * + * Misnamed and misappropriated! Taken from SWIG's type string manipulation utilities + * and modified to generate full (or partial) type qualifiers for method declarations, + * local variable declarations, and return value casting. More importantly, it merges + * parameter type information with actual parameter names to produce a complete method + * declaration that fully mirrors the original method declaration. + * + * There is almost certainly a saner way to do this. + * + * This function needs to be cleaned up and possibly split into several smaller + * functions. For instance, attaching default names to parameters should be done in a + * separate function. + * + */ + +String *method_decl(SwigType *s, const String_or_char *id, List *args, int strip, int values) { + String *result; + List *elements; + String *element = 0, *nextelement; + int is_const = 0; + int nelements, i; + int is_func = 0; + int arg_idx = 0; + + if (id) { + result = NewString(Char(id)); + } else { + result = NewString(""); + } + + elements = SwigType_split(s); + nelements = Len(elements); + if (nelements > 0) { + element = Getitem(elements, 0); + } + for (i = 0; i < nelements; i++) { + if (i < (nelements - 1)) { + nextelement = Getitem(elements, i+1); + } else { + nextelement = 0; + } + if (SwigType_isqualifier(element)) { + int skip = 0; + DOH *q = 0; + if (!strip) { + q = SwigType_parm(element); + if (!Cmp(q, "const")) { + is_const = 1; + is_func = SwigType_isfunction(nextelement); + if (is_func) skip = 1; + skip = 1; + } + if (!skip) { + Insert(result,0," "); + Insert(result,0,q); + } + Delete(q); + } + } else if (SwigType_ispointer(element)) { + Insert(result,0,"*"); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result,0,"("); + Append(result,")"); + } + } else if (SwigType_ismemberpointer(element)) { + String *q; + q = SwigType_parm(element); + Insert(result,0,"::*"); + Insert(result,0,q); + if ((nextelement) && ((SwigType_isfunction(nextelement) || (SwigType_isarray(nextelement))))) { + Insert(result,0,"("); + Append(result,")"); + } + Delete(q); + } + else if (SwigType_isreference(element)) { + Insert(result,0,"&"); + } else if (SwigType_isarray(element)) { + DOH *size; + Append(result,"["); + size = SwigType_parm(element); + Append(result,size); + Append(result,"]"); + Delete(size); + } else if (SwigType_isfunction(element)) { + Parm *parm; + String *p; + int j, plen; + Append(result,"("); + parm = args; + while (parm != 0) { + String *type = Getattr(parm, "type"); + String* name = Getattr(parm, "name"); + if (!name && Cmp(type, "void")) { + name = NewString(""); + Printf(name, "arg%d", arg_idx++); + Setattr(parm, "name", name); + } + if (!name) { + name = NewString(""); + } + p = SwigType_str(type, name); + Append(result,p); + String* value = Getattr(parm, "value"); + if (values && (value != 0)) { + Printf(result, " = %s", value); + } + parm = nextSibling(parm); + if (parm != 0) Append(result,", "); + } + Append(result,")"); + } else { + if (Strcmp(element,"v(...)") == 0) { + Insert(result,0,"..."); + } else { + String *bs = SwigType_namestr(element); + Insert(result,0," "); + Insert(result,0,bs); + Delete(bs); + } + } + element = nextelement; + } + Delete(elements); + if (is_const) { + if (is_func) { + Append(result, " "); + Append(result, "const"); + } else { + Insert(result, 0, "const "); + } + } + Chop(result); + return result; +} + + +/********************************************************************************** + * + * END OF TYPE UTILITY FUNCTIONS + * + **********************************************************************************/ + + #define PYSHADOW_MEMBER 0x2 static String *const_code = 0; @@ -31,8 +280,11 @@ static int shadow = 1; static int use_kw = 0; static File *f_runtime = 0; +static File *f_runtime_h = 0; static File *f_header = 0; static File *f_wrappers = 0; +static File *f_directors = 0; +static File *f_directors_h = 0; static File *f_init = 0; static File *f_shadow = 0; static File *f_shadow_stubs = 0; @@ -127,21 +379,35 @@ public: /* Initialize all of the output files */ String *outfile = Getattr(n,"outfile"); + String *outfile_h = Getattr(n, "outfile_h"); f_runtime = NewFile(outfile,"w"); if (!f_runtime) { Printf(stderr,"*** Can't open '%s'\n", outfile); SWIG_exit(EXIT_FAILURE); } + + if (CPlusPlus && directorsEnabled()) { + f_runtime_h = NewFile(outfile_h,"w"); + if (!f_runtime_h) { + Printf(stderr,"*** Can't open '%s'\n", outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } + f_init = NewString(""); f_header = NewString(""); f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); /* Register file targets with the SWIG file handler */ Swig_register_filebyname("header",f_header); Swig_register_filebyname("wrapper",f_wrappers); Swig_register_filebyname("runtime",f_runtime); Swig_register_filebyname("init",f_init); + Swig_register_filebyname("director",f_directors); + Swig_register_filebyname("director_h",f_directors_h); const_code = NewString(""); shadow_methods = NewString(""); @@ -157,6 +423,18 @@ public: module = Copy(Getattr(n,"name")); mainmodule = Getattr(n,"name"); + if (CPlusPlus) { + Swig_banner(f_directors_h); + Printf(f_directors_h, "#ifndef __%s_WRAP_H__\n", module); + Printf(f_directors_h, "#define __%s_WRAP_H__\n\n", module); + Printf(f_directors_h, "class __DIRECTOR__;\n\n"); + Printf(f_directors, "\n\n"); + Printf(f_directors, "/* ---------------------------------------------------\n"); + Printf(f_directors, " * C++ director class methods\n"); + Printf(f_directors, " * --------------------------------------------------- */\n\n"); + Printf(f_directors, "#include \"%s\"\n\n", outfile_h); + } + char filen[256]; /* If shadow classing is enabled, we're going to change the module name to "_module" */ @@ -184,7 +462,6 @@ public: // Python-2.2 object hack - Printv(f_shadow, "def _swig_setattr(self,class_type,name,value):\n", tab4, "if (name == \"this\"):\n", @@ -219,6 +496,17 @@ public: NIL); } + if (directorsEnabled()) { + // Try loading weakref.proxy, which is only available in Python 2.1 and higher + Printv(f_shadow, + "try:\n", + tab4, "from weakref import proxy as weakref_proxy\n", + "except:\n", + tab4, "weakref_proxy = lambda x: x\n", + "\n\n", + NIL); + } + // Include some information in the code Printf(f_header,"\n/*-----------------------------------------------\n @(target):= %s.so\n\ ------------------------------------------------*/\n", module); @@ -234,7 +522,7 @@ public: Printf(const_code,"static swig_const_info swig_const_table[] = {\n"); Printf(methods,"static PyMethodDef SwigMethods[] = {\n"); - /* emit code */ + /* emit code */ Language::top(n); /* Close language module */ @@ -260,12 +548,26 @@ public: /* Close all of the files */ Dump(f_header,f_runtime); + + if (CPlusPlus && directorsEnabled()) { + Dump(f_directors, f_runtime); + Dump(f_directors_h, f_runtime_h); + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif /* __%s_WRAP_H__ */\n", module); + Close(f_runtime_h); + } + Dump(f_wrappers,f_runtime); Wrapper_pretty_print(f_init,f_runtime); + Delete(f_header); Delete(f_wrappers); Delete(f_init); + Delete(f_directors); + Delete(f_directors_h); + Close(f_runtime); + return SWIG_OK; } @@ -304,6 +606,7 @@ public: String *iname = Getattr(n,"sym:name"); SwigType *d = Getattr(n,"type"); ParmList *l = Getattr(n,"parms"); + Node *parent = Getattr(n,"parentNode"); Parm *p; int i; @@ -324,6 +627,16 @@ public: int varargs = 0; int allow_kwargs = (use_kw || Getattr(n,"feature:kwargs")) ? 1 : 0; + /* member of a director class? */ + int director = Swig_directormethod(n); + int directorbase = Swig_directorbase(n); + Node *classNode = Swig_methodclass(n); + int hasVirtual = (classNode && (Getattr(classNode, "hasVirtual") != 0)); + String *nodeType = Getattr(n, "nodeType"); + int constructor = (!Cmp(nodeType, "constructor")); + String *storage = Getattr(n,"storage"); + int isVirtual = (Cmp(storage,"virtual") == 0); + if (Getattr(n,"sym:overloaded")) { overname = Getattr(n,"sym:overname"); } else { @@ -432,7 +745,7 @@ public: } Putc('O',parse_args); - Wrapper_add_localv(f, source, "PyObject *",source, " = 0", NIL); + Wrapper_add_localv(f, source, "PyObject *",source, "= 0", NIL); Printf(arglist,"&%s",source); if (i >= num_required) Printv(get_pointers, "if (", source, ") {\n", NIL); @@ -512,6 +825,47 @@ public: } } + /* if the object is a director, and the method call originated from its + * underlying python object, resolve the call by going up the c++ + * inheritance chain. otherwise try to resolve the method in python. + * without this check an infinite loop is set up between the director and + * shadow class method calls. + */ + + // NOTE: this code should only be inserted if this class is the + // base class of a director class. however, in general we haven't + // yet analyzed all classes derived from this one to see if they are + // directors. furthermore, this class may be used as the base of + // a director class defined in a completely different module at a + // later time, so this test must be included whether or not directorbase + // is true. we do skip this code if directors have not been enabled + // at the command line to preserve source-level compatibility with + // non-polymorphic swig. also, if this wrapper is for a smart-pointer + // method, there is no need to perform the test since the calling object + // (the smart-pointer) and the director object (the "pointee") are + // distinct. + + if (CPlusPlus && directorsEnabled()) { + if (!is_smart_pointer()) { + if (/*directorbase &&*/ hasVirtual && !constructor && isVirtual) { + Wrapper_add_local(f, "director", "__DIRECTOR__ *director = 0"); + Printf(f->code, "director = dynamic_cast<__DIRECTOR__*>(arg1);\n"); + Printf(f->code, "if (director && (director->__get_self()==obj0)) director->__set_up();\n"); + } + } + } + + /* for constructor, determine if Python class has been subclassed. + * if so, create a director instance. otherwise, just create a normal instance. + */ + /* MOVED TO Swig_ConstructorToFunction() */ + /* + if (constructor && (Getattr(n, "wrap:self") != 0)) { + Wrapper_add_local(f, "subclassed", "int subclassed = 0"); + Printf(f->code, "subclassed = (arg1 != Py_None);\n"); + } + */ + /* Emit the function call */ emit_action(n,f); @@ -527,7 +881,37 @@ public: } else { Replaceall(tm,"$owner","0"); } - Printf(f->code,"%s\n", tm); + + // FIXME: this will not try to unwrap directors returned as non-director + // base class pointers! + + /* New addition to unwrap director return values so that the original + * python object is returned instead. + */ + int unwrap = 0; + String *decl = Getattr(n, "decl"); + int is_pointer = SwigType_ispointer_return(decl); + int is_reference = SwigType_isreference_return(decl); + if (is_pointer || is_reference) { + String *type = Getattr(n, "type"); + //Node *classNode = Swig_methodclass(n); + //Node *module = Getattr(classNode, "module"); + Node *module = Getattr(parent, "module"); + Node *target = Swig_directormap(module, type); + if (target) unwrap = 1; + } + if (unwrap) { + Wrapper_add_local(f, "resultdirector", "__DIRECTOR__ *resultdirector = 0"); + Printf(f->code, "resultdirector = dynamic_cast<__DIRECTOR__*>(result);\n"); + Printf(f->code, "if (resultdirector) {\n"); + Printf(f->code, " resultobj = resultdirector->__get_self();\n"); + Printf(f->code, " Py_INCREF(resultobj);\n"); + Printf(f->code, "} else {\n"); + Printf(f->code,"%s\n", tm); + Printf(f->code, "}\n"); + } else { + Printf(f->code,"%s\n", tm); + } } else { Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(d,0), name); @@ -675,7 +1059,6 @@ public: * ------------------------------------------------------------ */ virtual int variableWrapper(Node *n) { - String *name = Getattr(n,"name"); String *iname = Getattr(n,"sym:name"); SwigType *t = Getattr(n,"type"); @@ -826,6 +1209,475 @@ public: return SWIG_OK; } + +/************************************************************************************* + * BEGIN C++ Director Class modifications + ************************************************************************************/ + +/* C++/Python polymorphism demo code, copyright (C) 2002 Mark Rose + * + * TODO + * + * Move some boilerplate code generation to Swig_...() functions. + * + */ + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Python object. + * + * --------------------------------------------------------------- */ + + int classDirectorMethod(Node *n, Node *parent, String *super) { + int is_void = 0; + int is_pointer = 0; + String *decl; + String *type; + String *name; + String *classname; + String *declaration; + ParmList *l; + Wrapper *w; + String *tm; + String *wrap_args; + String *return_type; + int status = SWIG_OK; + int idx; + + classname = Getattr(parent, "sym:name"); + type = Getattr(n, "type"); + name = Getattr(n, "name"); + + w = NewWrapper(); + declaration = NewString(""); + + /* determine if the method returns a pointer */ + decl = Getattr(n, "decl"); + is_pointer = SwigType_ispointer_return(decl); + is_void = (!Cmp(type, "void") && !is_pointer); + + /* form complete return type */ + return_type = Copy(type); + { + SwigType *t = Copy(decl); + SwigType *f = 0; + f = SwigType_pop_function(t); + SwigType_push(return_type, t); + Delete(f); + Delete(t); + } + + /* virtual method definition */ + l = Getattr(n, "parms"); + String *target; + String *pclassname = NewStringf("__DIRECTOR__%s", classname); + String *qualified_name = NewStringf("%s::%s", pclassname, name); + target = method_decl(decl, qualified_name, l, 0, 0); + String *rtype = SwigType_str(type, 0); + Printf(w->def, "%s %s {", rtype, target); + Delete(qualified_name); + Delete(target); + /* header declaration */ + target = method_decl(decl, name, l, 0, 1); + Printf(declaration, " virtual %s %s;\n", rtype, target); + Delete(target); + + /* attach typemaps to arguments (C/C++ -> Python) */ + String *arglist = NewString(""); + String* parse_args = NewString(""); + + Swig_typemap_attach_parms("in", l, w); + Swig_typemap_attach_parms("inv", l, w); + Swig_typemap_attach_parms("outv", l, w); + Swig_typemap_attach_parms("argoutv", l, w); + + Parm* p; + int num_arguments = emit_num_arguments(l); + int i; + char source[256]; + + wrap_args = NewString(""); + int outputs = 0; + if (!is_void) outputs++; + + /* build argument list and type conversion string */ + for (i=0, idx=0, p = l; i < num_arguments; i++) { + + while (Getattr(p, "tmap:ignore")) { + p = Getattr(p, "tmap:ignore:next"); + } + + if (Getattr(p, "tmap:argoutv") != 0) outputs++; + + String* pname = Getattr(p, "name"); + String* ptype = Getattr(p, "type"); + + Putc(',',arglist); + if ((tm = Getattr(p, "tmap:inv")) != 0) { + String* parse = Getattr(p, "tmap:inv:parse"); + if (!parse) { + sprintf(source, "obj%d", idx++); + Replaceall(tm, "$input", source); + Replaceall(tm, "$owner", "0"); + Printv(wrap_args, tm, "\n", NIL); + Wrapper_add_localv(w, source, "PyObject *", source, "= 0", NIL); + Printv(arglist, source, NIL); + Putc('O', parse_args); + } else { + Printf(parse_args, "%s", parse); + Replaceall(tm, "$input", pname); + Replaceall(tm, "$owner", "0"); + if (Len(tm) == 0) Append(tm, pname); + Printf(arglist, "%s", tm); + } + p = Getattr(p, "tmap:inv:next"); + continue; + } else + if (Cmp(ptype, "void")) { + /* special handling for pointers to other C++ director classes. + * ideally this would be left to a typemap, but there is currently no + * way to selectively apply the dynamic_cast<> to classes that have + * directors. in other words, the type "__DIRECTOR__$1_lname" only exists + * for classes with directors. we avoid the problem here by checking + * module.wrap::directormap, but it's not clear how to get a typemap to + * do something similar. perhaps a new default typemap (in addition + * to SWIGTYPE) called DIRECTORTYPE? + */ + if (SwigType_ispointer(ptype) || SwigType_isreference(ptype)) { + String *base = SwigType_base(ptype); + Node *module = Getattr(parent, "module"); + Node *target = Swig_directormap(module, ptype); + sprintf(source, "obj%d", idx++); + String *nonconst = 0; + /* strip pointer/reference --- should move to Swig/stype.c */ + String *nptype = NewString(Char(ptype)+2); + /* name as pointer */ + String *ppname = Copy(pname); + if (SwigType_isreference(ptype)) { + Insert(ppname,0,"&"); + } + /* if necessary, cast away const since Python doesn't support it! */ + if (SwigType_isconst(nptype)) { + nonconst = NewStringf("nc_tmp_%s", pname); + String *nonconst_i = NewStringf("= const_cast<%s>(%s)", SwigType_lstr(ptype, 0), ppname); + Wrapper_add_localv(w, nonconst, SwigType_lstr(ptype, 0), nonconst, nonconst_i, NIL); + Delete(nonconst_i); + Swig_warning(WARN_LANG_DISCARD_CONST, input_file, line_number, + "Target language argument '%s' discards const in director method %s::%s.\n", SwigType_str(ptype, pname), classname, name); + } else { + nonconst = Copy(ppname); + } + Delete(nptype); + Delete(ppname); + String *mangle = SwigType_manglestr(ptype); + if (target) { + String *director = NewStringf("director_%s", mangle); + Wrapper_add_localv(w, director, "__DIRECTOR__ *", director, "= 0", NIL); + Wrapper_add_localv(w, source, "PyObject *", source, "= 0", NIL); + Printf(wrap_args, "%s = dynamic_cast<__DIRECTOR__*>(%s);\n", director, nonconst); + Printf(wrap_args, "if (!%s) {\n", director); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", source, nonconst, mangle); + Printf(wrap_args, "} else {\n"); + Printf(wrap_args, "%s = %s->__get_self();\n", source, director); + Printf(wrap_args, "Py_INCREF(%s);\n", source); + Printf(wrap_args, "}\n"); + Printf(wrap_args, "assert(%s);\n", source); + Delete(director); + Printv(arglist, source, NIL); + } else { + Wrapper_add_localv(w, source, "PyObject *", source, "= 0", NIL); + Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE%s, 0);\n", + source, nonconst, mangle); + //Printf(wrap_args, "%s = SWIG_NewPointerObj(%s, SWIGTYPE_p_%s, 0);\n", + // source, nonconst, base); + Printv(arglist, source, NIL); + } + Putc('O', parse_args); + Delete(mangle); + Delete(nonconst); + } else { + Swig_warning(WARN_TYPEMAP_INV_UNDEF, input_file, line_number, + "Unable to use type %s as a function argument in director method %s::%s (skipping method).\n", SwigType_str(ptype, 0), classname, name); + status = SWIG_NOWRAP; + break; + } + } + p = nextSibling(p); + } + + /* declare method return value + * if the return value is a reference or const reference, a specialized typemap must + * handle it, including declaration of c_result ($result). + */ + if (!is_void) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(return_type, "c_result"), NIL); + } + /* declare Python return value */ + Wrapper_add_local(w, "result", "PyObject *result"); + + /* direct call to superclass if _up is set */ + Printf(w->code, "if (__get_up()) {\n"); + Printf(w->code, "return %s;\n", Swig_method_call(super,l)); + Printf(w->code, "}\n"); + + /* check that have a wrapped Python object */ + Printv(w->code, "assert(__get_self());\n", NIL); + + /* wrap complex arguments to PyObjects */ + Printv(w->code, wrap_args, NIL); + + /* pass the method call on to the Python object */ + if (Len(parse_args) > 0) { + Printf(w->code, "result = PyObject_CallMethod(__get_self(), \"%s\", \"%s\" %s);\n", name, parse_args, arglist); + } else { + Printf(w->code, "result = PyObject_CallMethod(__get_self(), \"%s\", NULL);\n", name); + } + + /* exception handling */ + tm = Swig_typemap_lookup_new("director:except", n, "result", 0); + if (!tm) { + tm = Getattr(n, "feature:director:except"); + } + if ((tm) && Len(tm) && (Strcmp(tm, "1") != 0)) { + Printf(w->code, "if (result == NULL) {\n"); + Printf(w->code, " PyObject *error = PyErr_Occurred();\n"); + Replaceall(tm, "$error", "error"); + Printv(w->code, Str(tm), "\n", NIL); + Printf(w->code, "}\n"); + } + + /* + * Python method may return a simple object, or a tuple. + * for in/out aruments, we have to extract the appropriate PyObjects from the tuple, + * then marshal everything back to C/C++ (return value and output arguments). + * + */ + + /* marshal return value and other outputs (if any) from PyObject to C/C++ type */ + + String* cleanup = NewString(""); + String* outarg = NewString(""); + + if (outputs > 1) { + Wrapper_add_local(w, "output", "PyObject *output"); + Printf(w->code, "if (!PyTuple_Check(result)) {\n"); + Printf(w->code, "throw SWIG_DIRECTOR_TYPE_MISMATCH(\"Python method failed to return a tuple.\");\n"); + Printf(w->code, "}\n"); + } + + idx = 0; + + /* marshal return value */ + if (!is_void) { + /* this seems really silly. the node's type excludes qualifier/pointer/reference markers, + * which have to be retrieved from the decl field to construct return_type. but the typemap + * lookup routine uses the node's type, so we have to swap in and out the correct type. + * it's not just me, similar silliness also occurs in Language::cDeclaration(). + */ + Setattr(n, "type", return_type); + tm = Swig_typemap_lookup_new("outv", n, "result", w); + Setattr(n, "type", type); + if (tm == 0) { + String *name = NewString("result"); + tm = Swig_typemap_search("outv", return_type, name, NULL); + Delete(name); + } + if (tm != 0) { + if (outputs > 1) { + Printf(w->code, "output = PyTuple_GetItem(result, %d);\n", idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", "result"); + } + /* TODO check this */ + if (Getattr(n,"wrap:disown")) { + Replaceall(tm,"$disown","SWIG_POINTER_DISOWN"); + } else { + Replaceall(tm,"$disown","0"); + } + Replaceall(tm, "$result", "c_result"); + Printv(w->code, tm, "\n", NIL); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, + "Unable to return type %s in director method %s::%s (skipping method).\n", SwigType_str(return_type, 0), classname, name); + status = SWIG_ERROR; + } + } + + /* marshal outputs */ + for (p = l; p; ) { + if ((tm = Getattr(p, "tmap:argoutv")) != 0) { + if (outputs > 1) { + Printf(w->code, "output = PyTuple_GetItem(result, %d);\n", idx++); + Replaceall(tm, "$input", "output"); + } else { + Replaceall(tm, "$input", "result"); + } + Replaceall(tm, "$result", Getattr(p, "name")); + Printv(w->code, tm, "\n", NIL); + p = Getattr(p, "tmap:argoutv:next"); + } else { + p = nextSibling(p); + } + } + + Printf(w->code, "Py_XDECREF(result);\n"); + + /* any existing helper functions to handle this? */ + if (!is_void) { + if (!SwigType_isreference(return_type)) { + Printf(w->code, "return c_result;\n"); + } else { + Printf(w->code, "return *c_result;\n"); + } + } + + Printf(w->code, "}\n"); + + /* emit the director method */ + if (status == SWIG_OK) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + } + + /* clean up */ + Delete(wrap_args); + Delete(parse_args); + Delete(arglist); + Delete(rtype); + Delete(return_type); + Delete(pclassname); + Delete(cleanup); + Delete(outarg); + DelWrapper(w); + return status; + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + int classDirectorConstructor(Node *n) { + Node *parent = Getattr(n, "parentNode"); + String *sub = NewString(""); + String *decl = Getattr(n, "decl"); + String *supername = Swig_class_name(parent); + String *classname = NewString(""); + Printf(classname, "__DIRECTOR__%s", supername); + + /* insert self and __disown parameters */ + Parm *p, *ip; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms = CopyParmList(superparms); + String *type = NewString("PyObject"); + SwigType_add_pointer(type); + p = NewParm(type, NewString("self")); + set_nextSibling(p, parms); + parms = p; + for (ip = parms; nextSibling(ip); ) ip = nextSibling(ip); + p = NewParm(NewString("int"), NewString("__disown")); + Setattr(p, "value", "1"); + set_nextSibling(ip, p); + + /* constructor */ + { + Wrapper *w = NewWrapper(); + String *call; + String *basetype = Getattr(parent, "classtype"); + String *target = method_decl(decl, classname, parms, 0, 0); + call = Swig_csuperclass_call(0, basetype, superparms); + Printf(w->def, "%s::%s: %s, __DIRECTOR__(self, __disown) { }", classname, target, call); + Delete(target); + Wrapper_print(w, f_directors); + Delete(call); + DelWrapper(w); + } + + /* constructor header */ + { + String *target = method_decl(decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + + Delete(sub); + Delete(classname); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname; + classname = Swig_class_name(n); + { + Wrapper *w = NewWrapper(); + Printf(w->def, "__DIRECTOR__%s::__DIRECTOR__%s(PyObject* self, int __disown): __DIRECTOR__(self, __disown) { }", classname, classname); + Wrapper_print(w, f_directors); + DelWrapper(w); + } + Printf(f_directors_h, " __DIRECTOR__%s(PyObject* self, int __disown = 1);\n", classname); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + + /* ------------------------------------------------------------ + * classDirectorInit() + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + String *declaration = Swig_director_declaration(n); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "%s\n", declaration); + Printf(f_directors_h, "public:\n"); + Delete(declaration); + return Language::classDirectorInit(n); + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + Printf(f_directors_h, "};\n\n"); + return Language::classDirectorEnd(n); + } + + /* ------------------------------------------------------------ + * classDirectorDisown() + * ------------------------------------------------------------ */ + + int classDirectorDisown(Node *n) { + int result; + int oldshadow = shadow; + /* disable shadowing */ + if (shadow) shadow = shadow | PYSHADOW_MEMBER; + result = Language::classDirectorDisown(n); + shadow = oldshadow; + if (shadow) { + String *symname = Getattr(n,"sym:name"); + String *mrename = Swig_name_disown(symname); //Getattr(n, "name")); + Printv(f_shadow, tab4, "def __disown__(self):\n", NIL); + Printv(f_shadow, tab8, "self.thisown = 0\n", NIL); + Printv(f_shadow, tab8, module, ".", mrename,"(self)\n", NIL); + Printv(f_shadow, tab8, "return weakref_proxy(self)\n", NIL); + Delete(mrename); + } + return result; + } + +/************************************************************************************* + * END of C++ Director Class modifications + ************************************************************************************/ + + /* ------------------------------------------------------------ * classDeclaration() * ------------------------------------------------------------ */ @@ -1038,11 +1890,37 @@ public: virtual int constructorHandler(Node *n) { String *symname = Getattr(n,"sym:name"); int oldshadow = shadow; + int use_director = Swig_directorclass(n); + /* + * If we wrapping the constructor of a C++ director class, prepend a new parameter + * to receive the scripting language object (e.g. 'self') + * + */ + Swig_save(&n,"parms",NIL); + if (use_director) { + Parm *parms = Getattr(n, "parms"); + Parm *self; + String *name = NewString("self"); + String *type = NewString("PyObject"); + SwigType_add_pointer(type); + self = NewParm(type, name); + Delete(type); + Delete(name); + Setattr(self, "lname", "O"); + if (parms) set_nextSibling(self, parms); + Setattr(n, "parms", self); + Setattr(n, "wrap:self", "1"); + Delete(self); + } + if (shadow) shadow = shadow | PYSHADOW_MEMBER; Language::constructorHandler(n); shadow = oldshadow; + Delattr(n, "wrap:self"); + Swig_restore(&n); + if (!Getattr(n,"sym:nextSibling")) { if (shadow) { int allow_kwargs = (use_kw || Getattr(n,"feature:kwargs")) ? 1 : 0; @@ -1051,16 +1929,30 @@ public: String *pycode = pythoncode(Getattr(n,"feature:shadow"),tab4); Printv(f_shadow,pycode,"\n",NIL); } else { + String *pass_self = NewString(""); + Node *parent = Swig_methodclass(n); + String *classname = Swig_class_name(parent); + if (use_director) { + Printv(pass_self, tab8, NIL); + Printf(pass_self, "if self.__class__ == %s:\n", classname); + Printv(pass_self, tab8, tab4, "args = (None,) + args\n", + tab8, "else:\n", + tab8, tab4, "args = (self,) + args\n", + NIL); + } if ((allow_kwargs) && (!Getattr(n,"sym:overloaded"))) { Printv(f_shadow, tab4, "def __init__(self,*args,**kwargs):\n", NIL); + Printv(f_shadow, pass_self, NIL); Printv(f_shadow, tab8, "self.this = apply(", module, ".", Swig_name_construct(symname), ",args,kwargs)\n", NIL); } else { Printv(f_shadow, tab4, "def __init__(self,*args):\n",NIL); + Printv(f_shadow, pass_self, NIL); Printv(f_shadow, tab8, "self.this = apply(", module, ".", Swig_name_construct(symname), ",args)\n", NIL); } Printv(f_shadow, tab8, "self.thisown = 1\n", NIL); + Delete(pass_self); } have_constructor = 1; } else { diff --git a/SWIG/Source/Modules/swigmod.h b/SWIG/Source/Modules/swigmod.h index a892c1d06..610a4321a 100644 --- a/SWIG/Source/Modules/swigmod.h +++ b/SWIG/Source/Modules/swigmod.h @@ -178,23 +178,48 @@ public: virtual int functionWrapper(Node *n); virtual int nativeWrapper(Node *n); + /* C++ director class generation */ + virtual int classDirector(Node *n); + virtual int classDirectorInit(Node *n); + virtual int classDirectorEnd(Node *n); + virtual int tagDirectorBases(Node *n); + virtual int unrollVirtualMethods(Node *n, + Node *parent, + Hash *vm, + int default_director, + int &virtual_destructor, + int &has_virtual); + virtual int classDirectorConstructor(Node *n); + virtual int classDirectorDefaultConstructor(Node *n); + virtual int classDirectorMethod(Node *n, Node *parent, String *super); + virtual int classDirectorConstructors(Node *n); + virtual int classDirectorMethods(Node *n); + virtual int classDirectorDisown(Node *n); + /* Miscellaneous */ virtual int validIdentifier(String *s); /* valid identifier? */ virtual int addSymbol(String *s, Node *n); /* Add symbol */ virtual Node *symbolLookup(String *s); /* Symbol lookup */ virtual Node *classLookup(SwigType *s); /* Class lookup */ + + /* Allow director related code generation */ + void allow_directors(int val = 1); + + /* Return true if directors are enabled */ + int directorsEnabled() const; + protected: /* Patch C++ pass-by-value */ static void patch_parms(Parm *p); - /* Allow overloaded functions */ - void allow_overloading(int val = 1); - /* Allow multiple-input typemaps */ void allow_multiple_input(int val = 1); + /* Allow overloaded functions */ + void allow_overloading(int val = 1); + /* Wrapping class query */ int is_wrapping_class(); @@ -210,11 +235,16 @@ public: /* Fully qualified type name to use */ String *getClassType() const; + /* Return true if the current method is part of a smart-pointer */ + int is_smart_pointer() const; + private: Hash *symbols; Hash *classtypes; int overloading; int multiinput; + int directors; + }; extern int SWIG_main(int, char **, Language *); diff --git a/SWIG/Source/Swig/cwrap.c b/SWIG/Source/Swig/cwrap.c index 5abcab2ab..6bc50cc12 100644 --- a/SWIG/Source/Swig/cwrap.c +++ b/SWIG/Source/Swig/cwrap.c @@ -341,13 +341,17 @@ Swig_cconstructor_call(String_or_char *name) { * ----------------------------------------------------------------------------- */ String * -Swig_cppconstructor_call(String_or_char *name, ParmList *parms) { +Swig_cppconstructor_base_call(String_or_char *name, ParmList *parms, int skip_self, int disown) { String *func; String *nname; int i = 0; int comma = 0; Parm *p = parms; SwigType *pt; + if (skip_self) { + if (p) p = nextSibling(p); + i++; + } nname = SwigType_namestr(name); func = NewString(""); Printf(func,"new %s(", nname); @@ -363,11 +367,29 @@ Swig_cppconstructor_call(String_or_char *name, ParmList *parms) { } p = nextSibling(p); } + if (disown >= 0) { + if (comma) Printf(func, ","); + Printf(func, "%d", disown); + } Printf(func,")"); Delete(nname); return func; } +String * +Swig_cppconstructor_call(String_or_char *name, ParmList *parms) { + return Swig_cppconstructor_base_call(name, parms, 0, -1); +} + +String * +Swig_cppconstructor_nodirector_call(String_or_char *name, ParmList *parms) { + return Swig_cppconstructor_base_call(name, parms, 1, -1); +} + +String * +Swig_cppconstructor_director_call(String_or_char *name, ParmList *parms) { + return Swig_cppconstructor_base_call(name, parms, 0, 0); +} /* ----------------------------------------------------------------------------- * Swig_cdestructor_call() @@ -473,7 +495,7 @@ Swig_MethodToFunction(Node *n, String *classname, int flags) { name = Getattr(n,"name"); qualifier = Getattr(n,"qualifier"); parms = CopyParmList(nonvoid_parms(Getattr(n,"parms"))); - + type = NewString(classname); if (qualifier) { SwigType_push(type,qualifier); @@ -524,6 +546,62 @@ Swig_MethodToFunction(Node *n, String *classname, int flags) { return SWIG_OK; } +/* ----------------------------------------------------------------------------- + * Swig_methodclass() + * + * This function returns the class node for a given method or class. + * ----------------------------------------------------------------------------- */ + +Node* +Swig_methodclass(Node *n) { + Node* type = Getattr(n, "nodeType"); + if (!Cmp(type, "class")) return n; + return Getattr(n, "parentNode"); +} + +int +Swig_directorbase(Node *n) { + Node *classNode = Swig_methodclass(n); + return (classNode && (Getattr(classNode, "directorBase") != 0)); +} + +int +Swig_directorclass(Node *n) { + Node *classNode = Swig_methodclass(n); + return (Getattr(classNode, "vtable") != 0); +} + +int +Swig_directormethod(Node *n) { + Node *classNode = Swig_methodclass(n); + if (classNode) { + Node *vtable = Getattr(classNode, "vtable"); + if (vtable) { + String *name = Getattr(n, "name"); + String *decl = Getattr(n, "decl"); + String *method_id = NewStringf("%s|%s", name, decl); + Hash *item = Getattr(vtable, method_id); + Delete(method_id); + if (item) { + return (Getattr(item, "director") != 0); + } + } + } + return 0; +} + +Node * +Swig_directormap(Node *module, String *type) { + int is_void = !Cmp(type, "void"); + if (!is_void && module) { + String* base = SwigType_base(type); + Node *directormap = Getattr(module, "wrap:directormap"); + if (directormap) return Getattr(directormap, base); + } + return 0; +} + + /* ----------------------------------------------------------------------------- * Swig_ConstructorToFunction() * @@ -537,10 +615,17 @@ Swig_ConstructorToFunction(Node *n, String *classname, int cplus, int flags) SwigType *type; String *membername; String *mangled; + Node *classNode; + int use_director; + + classNode = Swig_methodclass(n); + use_director = Swig_directorclass(n); + membername = Swig_name_construct(classname); mangled = Swig_name_mangle(membername); parms = CopyParmList(nonvoid_parms(Getattr(n,"parms"))); + type = NewString(classname); SwigType_add_pointer(type); @@ -558,7 +643,27 @@ Swig_ConstructorToFunction(Node *n, String *classname, int cplus, int flags) Setattr(n,"wrap:action", Swig_cresult(type,"result", Swig_cfunction_call(mangled,parms))); } else { if (cplus) { - Setattr(n,"wrap:action", Swig_cresult(type,"result", Swig_cppconstructor_call(classname,parms))); + /* if a C++ director class exists, create it rather than the original class */ + if (use_director) { + Node *parent = Swig_methodclass(n); + String *name = Getattr(parent, "sym:name"); + String* directorname = NewStringf("__DIRECTOR__%s", name); + String* action = NewString(""); + /* if Python class has been subclassed, create a director instance. + * otherwise, just create a normal instance. + */ + Printv(action, "if (arg1 != Py_None) { // subclassed\n", + Swig_cresult(type, "result", Swig_cppconstructor_director_call(directorname, parms)), + "} else {\n", + Swig_cresult(type, "result", Swig_cppconstructor_nodirector_call(classname, parms)), + "}\n", + NULL); + Setattr(n, "wrap:action", action); + Delete(action); + Delete(directorname); + } else { + Setattr(n,"wrap:action", Swig_cresult(type,"result", Swig_cppconstructor_call(classname,parms))); + } } else { Setattr(n,"wrap:action", Swig_cresult(type,"result", Swig_cconstructor_call(classname))); } @@ -583,7 +688,8 @@ Swig_DestructorToFunction(Node *n, String *classname, int cplus, int flags) { SwigType *type; Parm *p; - + Node *classNode; + type = NewString(classname); SwigType_add_pointer(type); p = NewParm(type,"self"); @@ -606,7 +712,9 @@ Swig_DestructorToFunction(Node *n, String *classname, int cplus, int flags) Delete(mangled); } else { if (cplus) { - Setattr(n,"wrap:action", NewStringf("%s;\n", Swig_cppdestructor_call())); + String* action = NewString(""); + Printf(action, "%s;\n", Swig_cppdestructor_call()); + Setattr(n,"wrap:action", action); } else { Setattr(n,"wrap:action", NewStringf("%s;\n", Swig_cdestructor_call())); } diff --git a/SWIG/Source/Swig/naming.c b/SWIG/Source/Swig/naming.c index 2aa92db58..8f7c380ef 100644 --- a/SWIG/Source/Swig/naming.c +++ b/SWIG/Source/Swig/naming.c @@ -341,6 +341,40 @@ String *Swig_name_destroy(const String_or_char *classname) { return r; } + +/* ----------------------------------------------------------------------------- + * Swig_name_disown() + * + * Returns the name of the accessor function used to disown an object. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_disown(const String_or_char *classname) { + String *r; + String *f; + String *rclassname; + char *cname; + rclassname = SwigType_namestr(classname); + r = NewString(""); + if (!naming_hash) naming_hash = NewHash(); + f = Getattr(naming_hash,"disown"); + if (!f) { + Append(r,"disown_%c"); + } else { + Append(r,f); + } + + cname = Char(rclassname); + if ((strncmp(cname,"struct ", 7) == 0) || + ((strncmp(cname,"class ", 6) == 0)) || + ((strncmp(cname,"union ", 6) == 0))) { + cname = strchr(cname, ' ')+1; + } + Replace(r,"%c",cname, DOH_REPLACE_ANY); + Delete(rclassname); + return r; +} + + /* ----------------------------------------------------------------------------- * Swig_name_object_set() * diff --git a/SWIG/Source/Swig/stype.c b/SWIG/Source/Swig/stype.c index 0ef12b983..a14828229 100644 --- a/SWIG/Source/Swig/stype.c +++ b/SWIG/Source/Swig/stype.c @@ -347,6 +347,7 @@ SwigType_function_parms(SwigType *t) { return firstp; } + /* ----------------------------------------------------------------------------- * SwigType_add_template() * @@ -561,6 +562,7 @@ String *SwigType_parm(SwigType *t) { /* ----------------------------------------------------------------------------- * SwigType_ispointer() + * SwigType_ispointer_return() * SwigType_isarray() * SwigType_isreference() * SwigType_isfunction() @@ -584,6 +586,30 @@ int SwigType_ispointer(SwigType *t) { return 0; } +int SwigType_ispointer_return(SwigType *t) { + char* c; + int idx; + if (!t) return 0; + c = Char(t); + idx = strlen(c)-4; + if (idx >= 0) { + return (strcmp(c+idx, ").p.") == 0); + } + return 0; +} + +int SwigType_isreference_return(SwigType *t) { + char* c; + int idx; + if (!t) return 0; + c = Char(t); + idx = strlen(c)-4; + if (idx >= 0) { + return (strcmp(c+idx, ").r.") == 0); + } + return 0; +} + int SwigType_ismemberpointer(SwigType *t) { char *c; if (!t) return 0; diff --git a/SWIG/Source/Swig/swig.h b/SWIG/Source/Swig/swig.h index 9ba11f118..ba87eb259 100644 --- a/SWIG/Source/Swig/swig.h +++ b/SWIG/Source/Swig/swig.h @@ -213,8 +213,10 @@ extern String *SwigType_lcaststr(SwigType *s, const String_or_char *id); extern String *SwigType_manglestr(SwigType *t); extern SwigType *SwigType_ltype(SwigType *t); extern int SwigType_ispointer(SwigType *t); +extern int SwigType_ispointer_return(SwigType *t); extern int SwigType_ismemberpointer(SwigType *t); extern int SwigType_isreference(SwigType *t); +extern int SwigType_isreference_return(SwigType *t); extern int SwigType_isarray(SwigType *t); extern int SwigType_isfunction(SwigType *t); extern int SwigType_isqualifier(SwigType *t); @@ -378,6 +380,7 @@ extern String *Swig_name_set(const String_or_char *vname); extern String *Swig_name_construct(const String_or_char *classname); extern String *Swig_name_copyconstructor(const String_or_char *classname); extern String *Swig_name_destroy(const String_or_char *classname); +extern String *Swig_name_disown(const String_or_char *classname); /* --- parameterized rename functions --- */ @@ -443,6 +446,13 @@ extern int Swig_VarsetToFunction(Node *n); #define CWRAP_EXTEND 0x01 #define CWRAP_SMART_POINTER 0x02 +/* --- Director Helpers --- */ +extern Node *Swig_methodclass(Node *n); +extern int Swig_directorbase(Node *n); +extern int Swig_directorclass(Node *n); +extern int Swig_directormethod(Node *n); +extern Node *Swig_directormap(Node *n, String *type); + /* --- Legacy Typemap API (somewhat simplified, ha!) --- */ extern void Swig_typemap_init();