fix rich compare

This commit is contained in:
David Rose 2013-02-20 00:37:12 +00:00
parent c5bc7790ae
commit 53b472756b
2 changed files with 47 additions and 21 deletions

View File

@ -1605,21 +1605,24 @@ write_module_class(ostream &out, Object *obj) {
}
if (NeedsARichCompareFunction(obj->_itype)) {
//NB. It's a bit inefficient to first pack the 'other' arg into a tuple only to be
// parsed by PyArg_Parse again later, but there's no obvious other way to do it.
// NB. It's a bit inefficient to first pack the 'other' arg into a
// tuple only to be parsed by PyArg_Parse again later, but there's
// no obvious other way to do it.
out << "//////////////////\n";
out << "// A rich comparison function\n";
out << "// " << ClassName << "\n";
out << "//////////////////\n";
out << "static PyObject *Dtool_RichCompare_" << ClassName << "(PyObject *self, PyObject *other, int op) {\n";
out << " PyObject *args = PyTuple_Pack(1, other);\n";
out << " PyObject *kwds = NULL;\n";
out << " " << cClassName << " *local_this = NULL;\n";
out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n";
out << " if (local_this == NULL) {\n";
out << " PyErr_SetString(PyExc_AttributeError, \"C++ object is not yet constructed, or already destructed.\");\n";
out << " return NULL;\n";
out << " }\n\n";
out << " }\n";
out << " PyObject *args = PyTuple_Pack(1, other);\n";
string args_cleanup = "Py_DECREF(args);";
out << "\n";
out << " switch (op) {\n";
for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi) {
@ -1654,13 +1657,20 @@ write_module_class(ostream &out, Object *obj) {
}
ostringstream forward_decl;
string expected_params;
write_function_forset(out, obj, func, remaps, expected_params, 2, forward_decl, false);
write_function_forset(out, obj, func, remaps, expected_params, 2, forward_decl, false, args_cleanup);
out << " if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError)) {\n";
out << " PyErr_Clear();\n";
out << " }\n";
out << " break;\n";
has_local_richcompare = true;
}
out << " }\n";
out << " Py_DECREF(args);\n";
out << " " << args_cleanup << "\n";
out << " if (PyErr_Occurred()) {\n";
out << " return (PyObject *)NULL;\n";
out << " }\n";
out << " Py_INCREF(Py_NotImplemented);\n";
out << " return Py_NotImplemented;\n";
out << "}\n\n";
@ -2032,7 +2042,7 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
for (mii = MapSets.begin(); mii != MapSets.end(); mii ++) {
indent(out, 2) << "case " << mii->first << ": {\n";
write_function_forset(out, obj, func, mii->second, expected_params, 4, forward_decl, is_inplace);
write_function_forset(out, obj, func, mii->second, expected_params, 4, forward_decl, is_inplace, "");
if ((*mii->second.begin())->_type == FunctionRemap::T_constructor) {
constructor = true;
}
@ -2097,7 +2107,7 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
} else {
string expected_params = "";
for (mii = MapSets.begin(); mii != MapSets.end(); mii++) {
write_function_forset(out, obj, func, mii->second, expected_params, 2, forward_decl, is_inplace);
write_function_forset(out, obj, func, mii->second, expected_params, 2, forward_decl, is_inplace, "");
if ((*mii->second.begin())->_type == FunctionRemap::T_constructor) {
constructor = true;
}
@ -2245,7 +2255,8 @@ write_function_forset(ostream &out, InterfaceMaker::Object *obj,
InterfaceMaker::Function *func,
std::set<FunctionRemap *> &remapsin,
string &expected_params, int indent_level,
ostream &forward_decl, bool is_inplace) {
ostream &forward_decl, bool is_inplace,
const string &args_cleanup) {
// Do we accept any parameters that are class objects? If so, we
// might need to check for parameter coercion.
bool coercion_possible = false;
@ -2315,7 +2326,7 @@ write_function_forset(ostream &out, InterfaceMaker::Object *obj,
indent(out, indent_level) << "// -2 ";
remap->write_orig_prototype(out, 0); out << "\n";
write_function_instance(out, obj, func, remap, expected_params, indent_level + 2, false, forward_decl, func->_name, is_inplace, coercion_possible);
write_function_instance(out, obj, func, remap, expected_params, indent_level + 2, false, forward_decl, func->_name, is_inplace, coercion_possible, args_cleanup);
indent(out, indent_level + 2) << "PyErr_Clear(); \n";
indent(out, indent_level) << "}\n\n";
@ -2342,7 +2353,7 @@ write_function_forset(ostream &out, InterfaceMaker::Object *obj,
<< "// 1-" ;
remap->write_orig_prototype(out, 0);
out << "\n" ;
write_function_instance(out, obj, func, remap, expected_params, indent_level + 2, true, forward_decl, func->_name, is_inplace, coercion_possible);
write_function_instance(out, obj, func, remap, expected_params, indent_level + 2, true, forward_decl, func->_name, is_inplace, coercion_possible, args_cleanup);
if (remap->_has_this && !remap->_const_method) {
indent(out, indent_level)
@ -2355,6 +2366,10 @@ write_function_forset(ostream &out, InterfaceMaker::Object *obj,
<< classNameFromCppName(class_name, false)
<< "." << methodNameFromCppName(func, class_name, false)
<< "() on a const object.\");\n";
if (!args_cleanup.empty()) {
indent(out, indent_level + 2)
<< args_cleanup << "\n";
}
indent(out, indent_level + 2)
<< "return (PyObject *) NULL;\n";
indent(out, indent_level)
@ -2420,7 +2435,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
int indent_level, bool errors_fatal,
ostream &ForwardDeclrs,
const std::string &functionnamestr, bool is_inplace,
bool coercion_possible) {
bool coercion_possible, const string &args_cleanup) {
string format_specifiers;
std::string keyword_list;
string parameter_list;
@ -2788,6 +2803,10 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
indent(out, extra_indent_level + 2)
<< "Py_XDECREF(coerced);\n";
}
if (!args_cleanup.empty()) {
indent(out, extra_indent_level + 2)
<< args_cleanup << "\n";
}
indent(out, extra_indent_level + 2)
<< "PyErr_SetString(PyExc_IndexError, \"Out of bounds.\");\n";
indent(out, extra_indent_level + 2)
@ -2835,7 +2854,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
}
return_expr = manage_return_value(out, 4, remap, "return_value");
do_assert_init(out, extra_indent_level,is_constructor);
do_assert_init(out, extra_indent_level, is_constructor, args_cleanup);
pack_return_value(out, extra_indent_level, remap, return_expr, ForwardDeclrs, is_inplace);
} else {
@ -2869,7 +2888,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
indent(out, extra_indent_level)
<< "Py_XDECREF(coerced);\n";
}
do_assert_init(out, extra_indent_level,is_constructor);
do_assert_init(out, extra_indent_level, is_constructor, args_cleanup);
indent(out, extra_indent_level) << "return Py_BuildValue(\"\");\n";
} else {
@ -2899,7 +2918,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
indent(out, extra_indent_level)
<< "Py_XDECREF(coerced);\n";
}
do_assert_init(out, extra_indent_level,is_constructor);
do_assert_init(out, extra_indent_level, is_constructor, args_cleanup);
pack_return_value(out, extra_indent_level, remap, remap->_return_type->temporary_to_return(return_expr), ForwardDeclrs, is_inplace);
}
}
@ -3168,7 +3187,7 @@ pack_return_value(ostream &out, int indent_level,
}
else
{
indent(out, indent_level) << " Shouln Never Reach This InterfaceMakerPythonNative::pack_return_value";
indent(out, indent_level) << " Should Never Reach This InterfaceMakerPythonNative::pack_return_value";
//<< "return PyInt_FromLong((int)" << return_expr << ");\n";
}
@ -3545,7 +3564,7 @@ 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 string &args_cleanup) const {
// If a method raises TypeError, continue.
indent(out, indent_level)
<< "if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError)) {\n";
@ -3559,6 +3578,11 @@ void InterfaceMakerPythonNative::do_assert_init(ostream &out, int &indent_level,
<< "} else {\n";
indent_level += 2;
if (!args_cleanup.empty()) {
indent(out, indent_level)
<< args_cleanup << "\n";
}
if (watch_asserts) {
out << "#ifndef NDEBUG\n";
indent(out, indent_level)
@ -3907,7 +3931,6 @@ NeedsARichCompareFunction(const InterrogateType &itype_class) {
for (mi = 0; mi < num_methods; ++mi) {
FunctionIndex func_index = itype_class.get_method(mi);
const InterrogateFunction &ifunc = idb->get_function(func_index);
int op;
if (ifunc.get_name() == "operator <") {
return true;
}

View File

@ -92,10 +92,13 @@ private:
FunctionRemap *remap, string &expected_params,
int indent_level, bool errors_fatal,
ostream &forwarddecl, const std::string &functionnamestr,
bool is_inplace, bool coercion_possible);
bool is_inplace, bool coercion_possible,
const string &args_cleanup);
void write_function_forset(ostream &out, Object *obj, Function *func,
std::set<FunctionRemap*> &remaps, string &expected_params, int indent_level, ostream &forwarddecl, bool inplace);
std::set<FunctionRemap*> &remaps, string &expected_params,
int indent_level, ostream &forwarddecl, bool inplace,
const string &args_cleanup);
void pack_return_value(ostream &out, int indent_level,
FunctionRemap *remap, std::string return_expr, ostream &forwarddecl, bool in_place);
@ -107,7 +110,7 @@ private:
void write_class_declarations(ostream &out, ostream *out_h, Object *obj);
void write_class_details(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 string &args_cleanup) const;
public:
bool isRemapLegal(FunctionRemap &remap);
bool isFunctionLegal( Function *func);