Răsfoiți Sursa

lists and strings will be automatically coerced into a PTA_blah

David Rose 16 ani în urmă
părinte
comite
a942ce5fbf

+ 43 - 12
dtool/src/interrogate/functionRemap.cxx

@@ -307,7 +307,18 @@ make_wrapper_entry(FunctionIndex function_index) {
       _parameters.erase(_parameters.begin() + 1);
       _flags |= F_explicit_self;
     }
+
+  } else if (_type == T_constructor) {
+    // We also allow "self" to be passed in to a constructor, even
+    // though the constructor doesn't normally accept a this pointer.
+    // But this makes sense to Python programmers.
+    if (_parameters.size() >= 1 && _parameters[0]._name == "self" &&
+        TypeManager::is_pointer_to_PyObject(_parameters[0]._remap->get_orig_type())) {
+      _parameters.erase(_parameters.begin() + 0);
+      _flags |= F_explicit_self;
+    }
   }
+      
 
   if (!_void_return) {
     iwrapper._flags |= InterrogateFunctionWrapper::F_has_return;
@@ -391,24 +402,21 @@ get_call_str(const string &container, const vector_string &pexprs) const {
       call << _cppfunc->get_local_name(&parser);
     }
 
+    const char *separator = "";
+
     call << "(";
     if (_flags & F_explicit_self) {
       // Pass on the PyObject * that we stripped off above.
-      call << "self";
-      if (_first_true_parameter < (int)_parameters.size()) {
-        call << ", ";
-      }
+      call << separator << "self";
+      separator = ", ";
     }
 
-    int pn = _first_true_parameter;
-    if (pn < (int)_parameters.size()) {
+    for (int pn = _first_true_parameter;
+         pn < (int)_parameters.size();
+         ++pn) {
+      call << separator;
       _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
-      pn++;
-      while (pn < (int)_parameters.size()) {
-        call << ", ";
-        _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
-        pn++;
-      }
+      separator = ", ";
     }
     call << ")";
   }
@@ -670,3 +678,26 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
 
   return true;
 }
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+std::string make_safe_name(const std::string & name)
+{
+    return InterrogateBuilder::clean_identifier(name);
+
+    /*
+    static const char safe_chars2[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+        std::string result = name;
+
+        size_t pos = result.find_first_not_of(safe_chars2);
+        while (pos != std::string::npos)
+        {
+                result[pos] = '_';
+                pos = result.find_first_not_of(safe_chars2);
+        }
+
+        return result;
+        */
+}

+ 3 - 0
dtool/src/interrogate/functionRemap.h

@@ -126,4 +126,7 @@ private:
   bool setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_maker);
 };
 
+std::string make_safe_name(const std::string & name);
+
+
 #endif

+ 51 - 31
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -335,28 +335,6 @@ std::string  methodNameFromCppName(InterfaceMaker::Function *func, const std::st
 ///////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////
 
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-std::string make_safe_name(const std::string & name)
-{
-    return InterrogateBuilder::clean_identifier(name);
-
-    /*
-    static const char safe_chars2[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
-        std::string result = name;
-
-        size_t pos = result.find_first_not_of(safe_chars2);
-        while (pos != std::string::npos)
-        {
-                result[pos] = '_';
-                pos = result.find_first_not_of(safe_chars2);
-        }
-
-        return result;
-        */
-}
-
 bool isInplaceFunction(InterfaceMaker::Function *func)
 {
     std::string wname = methodNameFromCppName(func,"");
@@ -2368,6 +2346,24 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
   if (remap->_type == FunctionRemap::T_constructor) {
     is_constructor = true;
   }
+  
+  if (is_constructor && (remap->_flags & FunctionRemap::F_explicit_self) != 0) {
+    // If we'll be passing "self" to the constructor, we need to
+    // pre-initialize it here.  Unfortunately, we can't pre-load the
+    // "this" pointer, but the constructor itself can do this.
+    
+    indent(out, indent_level)
+      << "// Pre-initialize self for the constructor\n";
+
+    CPPType *orig_type = remap->_return_type->get_orig_type();
+    TypeIndex type_index = builder.get_type(TypeManager::unwrap(TypeManager::resolve_type(orig_type)),false);
+    InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
+    const InterrogateType &itype = idb->get_type(type_index);    
+    indent(out, indent_level)
+      << "DTool_PyInit_Finalize(self, NULL, &" 
+      << CLASS_PREFEX << make_safe_name(itype.get_scoped_name())
+      << ", false, false);\n";
+  }
 
   // Make one pass through the parameter list.  We will output a
   // one-line temporary variable definition for each parameter, while
@@ -2790,6 +2786,11 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
     }
   }
 
+  // Close the extra brace opened within do_assert_init().
+  extra_indent_level -= 2;
+  indent(out, extra_indent_level)
+    << "}\n";
+
   if (!extra_param_check.empty()) {
     extra_indent_level-=4;
     indent(out,extra_indent_level)<< "}\n";
@@ -3382,7 +3383,20 @@ bool InterfaceMakerPythonNative::isFunctionWithThis( Function *func)
 //               failed while the C++ code was executing, and report
 //               this failure back to Python.
 ////////////////////////////////////////////////////////////////////
-void InterfaceMakerPythonNative::do_assert_init(ostream &out, int indent_level, bool constructor) const {
+void InterfaceMakerPythonNative::do_assert_init(ostream &out, int &indent_level, bool constructor) const {
+  // If a method raises TypeError, continue.
+  indent(out, indent_level)
+    << "if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError)) {\n";
+  indent(out, indent_level + 2)
+    << "// TypeError raised; continue to next overload type.\n";
+  if (constructor) {
+    indent(out, indent_level + 2)
+      << "delete return_value;\n";
+  }
+  indent(out, indent_level)
+    << "} else {\n";
+  indent_level += 2;
+
   if (watch_asserts) {
     out << "#ifndef NDEBUG\n";
     indent(out, indent_level)
@@ -3393,19 +3407,25 @@ void InterfaceMakerPythonNative::do_assert_init(ostream &out, int indent_level,
       << "PyErr_SetString(PyExc_AssertionError, notify->get_assert_error_message().c_str());\n";
     indent(out, indent_level + 2)
       << "notify->clear_assert_failed();\n";
-    if(constructor)
-        indent(out, indent_level + 2) << "return -1;\n";
-    else
-        indent(out, indent_level + 2) << "return (PyObject *)NULL;\n";
+    if (constructor) {
+      indent(out, indent_level + 2) << "delete return_value;\n";
+      indent(out, indent_level + 2) << "return -1;\n";
+    } else {
+      indent(out, indent_level + 2) << "return (PyObject *)NULL;\n";
+    }
+
     indent(out, indent_level)
       << "}\n";
     out << "#endif\n";
     indent(out, indent_level)
       << "if (PyErr_Occurred()) {\n";
-    if(constructor)
-        indent(out, indent_level + 2) << "return -1;\n";
-    else
-        indent(out, indent_level + 2) << "return (PyObject *)NULL;\n";
+    if (constructor) {
+      indent(out, indent_level + 2) << "delete return_value;\n";
+      indent(out, indent_level + 2) << "return -1;\n";
+    } else {
+      indent(out, indent_level + 2) << "return (PyObject *)NULL;\n";
+    }
+
     indent(out, indent_level)
       << "}\n";
   }

+ 1 - 1
dtool/src/interrogate/interfaceMakerPythonNative.h

@@ -107,7 +107,7 @@ private:
   void write_ClasseDeclarations(ostream &out ,  ostream *out_h,Object * obj);
   void write_ClasseDetails(ostream &out, Object * obj);
   
-  void do_assert_init(ostream &out, int indent_level, bool constructor) const;
+  void do_assert_init(ostream &out, int &indent_level, bool constructor) const;
 public:
   bool isRemapLegal( FunctionRemap &remap);
   bool isFunctionLegal( Function *func);

+ 2 - 0
dtool/src/pystub/pystub.cxx

@@ -99,6 +99,7 @@ extern "C" {
   EXPCL_DTOOLCONFIG int PyString_AsStringAndSize(...);
   EXPCL_DTOOLCONFIG int PyString_FromString(...);
   EXPCL_DTOOLCONFIG int PyString_FromStringAndSize(...);
+  EXPCL_DTOOLCONFIG int PyString_Size(...);
   EXPCL_DTOOLCONFIG int PyString_Type(...);
   EXPCL_DTOOLCONFIG int PySys_GetObject(...);
   EXPCL_DTOOLCONFIG int PyThreadState_Clear(...);
@@ -231,6 +232,7 @@ int PyString_AsString(...) { return 0; }
 int PyString_AsStringAndSize(...) { return 0; }
 int PyString_FromString(...) { return 0; }
 int PyString_FromStringAndSize(...) { return 0; }
+int PyString_Size(...) { return 0; }
 int PyString_Type(...) { return 0; }
 int PySys_GetObject(...) { return 0; }
 int PyThreadState_Clear(...) { return 0; }

+ 71 - 0
panda/src/express/pointerToArray.I

@@ -77,6 +77,77 @@ PointerToArray(const PointerToArray<Element> &copy) :
 {
 }
 
+#ifdef HAVE_PYTHON
+////////////////////////////////////////////////////////////////////
+//     Function: PointerToArray::Constructor
+//       Access: Published
+//  Description: This special constructor accepts a Python list of
+//               elements, or a Python string.
+////////////////////////////////////////////////////////////////////
+template<class Element>
+PointerToArray<Element>::
+PointerToArray(PyObject *self, PyObject *sequence) :
+  PointerToArrayBase<Element>((ReferenceCountedVector<Element> *)NULL),
+  _type_handle(get_type_handle(Element))
+{
+  // We have to pre-initialize self's "this" pointer when we receive
+  // self in the constructor--the caller can't initialize this for us.
+  ((Dtool_PyInstDef *)self)->_ptr_to_object = this;
+
+  if (!PySequence_Check(sequence)) {
+    // If passed with a non-sequence, this isn't the right constructor.
+    PyErr_SetString(PyExc_TypeError, "PointerToArray constructor requires a sequence");
+    return;
+  }
+
+  if (PyString_CheckExact(sequence)) {
+    // If we were passed a Python string, then instead of storing it
+    // character-at-a-time, just load the whole string as a data
+    // buffer.
+    int size = PyString_Size(sequence);
+    if (size % sizeof(Element) != 0) {
+      ostringstream stream;
+      stream << "Buffer not a multiple of " << sizeof(Element) << " bytes";
+      string str = stream.str();
+      PyErr_SetString(PyExc_ValueError, str.c_str());
+      return;
+    }
+      
+    int num_elements = size / sizeof(Element);
+    insert(begin(), num_elements, Element());
+
+    // Hope there aren't any constructors or destructors involved
+    // here.
+    if (size != 0) {
+      const char *data = PyString_AsString(sequence);
+      memcpy(p(), data, size);
+    }
+    return;
+  }
+
+  // Now construct the internal list by copying the elements
+  // one-at-a-time from Python.
+  int size = PySequence_Size(sequence);
+  for (int i = 0; i < size; ++i) {
+    PyObject *item = PySequence_GetItem(sequence, i);
+    if (item == NULL) {
+      return;
+    }
+    PyObject *result = PyObject_CallMethod(self, (char *)"pushBack", (char *)"O", item);
+    Py_DECREF(item);
+    if (result == NULL) {
+      // Unable to add item--probably it wasn't of the appropriate type.
+      ostringstream stream;
+      stream << "Element " << i << " in sequence passed to PointerToArray constructor could not be added";
+      string str = stream.str();
+      PyErr_SetString(PyExc_TypeError, str.c_str());
+      return;
+    }
+    Py_DECREF(result);
+  }
+}
+#endif  // HAVE_PYTHON
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PointerToArray::begin
 //       Access: Public

+ 13 - 0
panda/src/express/pointerToArray.h

@@ -67,6 +67,9 @@
 #include "pandabase.h"
 
 #include "pointerToArrayBase.h"
+#ifdef HAVE_PYTHON
+#include "py_panda.h"
+#endif
 
 #if defined(WIN32_VC) && !defined(__INTEL_COMPILER)
 // disable mysterious MSVC warning for static inline PTA::empty_array method
@@ -108,6 +111,11 @@ PUBLISHED:
   INLINE PointerToArray(TypeHandle type_handle = get_type_handle(Element));
   INLINE static PointerToArray<Element> empty_array(size_type n, TypeHandle type_handle = get_type_handle(Element));
   INLINE PointerToArray(const PointerToArray<Element> &copy);
+
+#ifdef HAVE_PYTHON
+  PointerToArray(PyObject *self, PyObject *sequence);
+#endif
+
   INLINE size_type size() const;
   INLINE void push_back(const Element &x);
   INLINE void pop_back();
@@ -141,6 +149,10 @@ public:
   INLINE PointerToArray(size_type n, const Element &value, TypeHandle type_handle = get_type_handle(Element));
   INLINE PointerToArray(const PointerToArray<Element> &copy);
 
+#ifdef HAVE_PYTHON
+  PointerToArray(PyObject *self, PyObject *sequence);
+#endif
+
 public:
   // Duplicating the interface of vector.  The following member
   // functions are all const, because they do not reassign the
@@ -254,6 +266,7 @@ public:
 PUBLISHED:
   INLINE ConstPointerToArray(const PointerToArray<Element> &copy);
   INLINE ConstPointerToArray(const ConstPointerToArray<Element> &copy);
+
   typedef TYPENAME pvector<Element>::size_type size_type;
   INLINE size_type size() const;
   INLINE const Element &get_element(size_type n) const;

+ 12 - 15
panda/src/gobj/textureCollection.cxx

@@ -13,15 +13,11 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "textureCollection.h"
-
 #include "indent.h"
 
 #ifdef HAVE_PYTHON
-#include "py_panda.h"  
-#ifndef CPPPARSER
-extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_Texture;
-#endif  // CPPPARSER
-#endif  // HAVE_PYTHON
+#include "py_panda.h"
+#endif
 
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureCollection::Constructor
@@ -63,7 +59,11 @@ operator = (const TextureCollection &copy) {
 //               in the class record.
 ////////////////////////////////////////////////////////////////////
 TextureCollection::
-TextureCollection(PyObject *sequence) {
+TextureCollection(PyObject *self, PyObject *sequence) {
+  // We have to pre-initialize self's "this" pointer when we receive
+  // self in the constructor--the caller can't initialize this for us.
+  ((Dtool_PyInstDef *)self)->_ptr_to_object = this;
+
   if (!PySequence_Check(sequence)) {
     // If passed with a non-sequence, this isn't the right constructor.
     PyErr_SetString(PyExc_TypeError, "TextureCollection constructor requires a sequence");
@@ -76,20 +76,17 @@ TextureCollection(PyObject *sequence) {
     if (item == NULL) {
       return;
     }
-    Texture *tex = NULL;
-    DTOOL_Call_ExtractThisPointerForType(item, &Dtool_Texture, (void **)&tex);
+    PyObject *result = PyObject_CallMethod(self, (char *)"addTexture", (char *)"O", item);
     Py_DECREF(item);
-    if (tex == NULL) {
-      // If one of the items in the sequence is not a Texture, can't
-      // use this constructor.
+    if (result == NULL) {
+      // Unable to add item--probably it wasn't of the appropriate type.
       ostringstream stream;
-      stream << "Element " << i << " in sequence passed to TextureCollection constructor is not a Texture";
+      stream << "Element " << i << " in sequence passed to TextureCollection constructor could not be added";
       string str = stream.str();
       PyErr_SetString(PyExc_TypeError, str.c_str());
       return;
     }
-
-    add_texture(tex);
+    Py_DECREF(result);
   }
 }
 #endif  // HAVE_PYTHON

+ 1 - 1
panda/src/gobj/textureCollection.h

@@ -32,7 +32,7 @@ PUBLISHED:
   INLINE ~TextureCollection();
 
 #ifdef HAVE_PYTHON
-  TextureCollection(PyObject *sequence);
+  TextureCollection(PyObject *self, PyObject *sequence);
   PyObject *__reduce__(PyObject *self) const;
 #endif
 

+ 12 - 15
panda/src/pgraph/nodePathCollection.cxx

@@ -18,15 +18,11 @@
 #include "textureAttrib.h"
 #include "colorScaleAttrib.h"
 #include "colorAttrib.h"
-
 #include "indent.h"
 
 #ifdef HAVE_PYTHON
-#include "py_panda.h"  
-#ifndef CPPPARSER
-extern EXPCL_PANDA_PUTIL Dtool_PyTypedObject Dtool_NodePath;
-#endif  // CPPPARSER
-#endif  // HAVE_PYTHON
+#include "py_panda.h"
+#endif
 
 ////////////////////////////////////////////////////////////////////
 //     Function: NodePathCollection::Constructor
@@ -68,7 +64,11 @@ operator = (const NodePathCollection &copy) {
 //               in the class record.
 ////////////////////////////////////////////////////////////////////
 NodePathCollection::
-NodePathCollection(PyObject *sequence) {
+NodePathCollection(PyObject *self, PyObject *sequence) {
+  // We have to pre-initialize self's "this" pointer when we receive
+  // self in the constructor--the caller can't initialize this for us.
+  ((Dtool_PyInstDef *)self)->_ptr_to_object = this;
+
   if (!PySequence_Check(sequence)) {
     // If passed with a non-sequence, this isn't the right constructor.
     PyErr_SetString(PyExc_TypeError, "NodePathCollection constructor requires a sequence");
@@ -81,20 +81,17 @@ NodePathCollection(PyObject *sequence) {
     if (item == NULL) {
       return;
     }
-    NodePath *np = NULL;
-    DTOOL_Call_ExtractThisPointerForType(item, &Dtool_NodePath, (void **)&np);
+    PyObject *result = PyObject_CallMethod(self, (char *)"addPath", (char *)"O", item);
     Py_DECREF(item);
-    if (np == NULL) {
-      // If one of the items in the sequence is not a NodePath, can't
-      // use this constructor.
+    if (result == NULL) {
+      // Unable to add item--probably it wasn't of the appropriate type.
       ostringstream stream;
-      stream << "Element " << i << " in sequence passed to NodePathCollection constructor is not a NodePath";
+      stream << "Element " << i << " in sequence passed to NodePathCollection constructor could not be added";
       string str = stream.str();
       PyErr_SetString(PyExc_TypeError, str.c_str());
       return;
     }
-
-    add_path(*np);
+    Py_DECREF(result);
   }
 }
 #endif  // HAVE_PYTHON

+ 1 - 1
panda/src/pgraph/nodePathCollection.h

@@ -34,7 +34,7 @@ PUBLISHED:
   INLINE ~NodePathCollection();
 
 #ifdef HAVE_PYTHON
-  NodePathCollection(PyObject *sequence);
+  NodePathCollection(PyObject *self, PyObject *sequence);
   PyObject *__reduce__(PyObject *self) const;
 #endif