lists and strings will be automatically coerced into a PTA_blah

This commit is contained in:
David Rose 2010-02-11 22:38:34 +00:00
parent f59e128425
commit a942ce5fbf
11 changed files with 210 additions and 76 deletions

View File

@ -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;
*/
}

View File

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

View File

@ -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";
}

View File

@ -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);

View File

@ -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; }

View File

@ -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

View File

@ -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;

View File

@ -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

View File

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

View File

@ -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

View File

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