271 lines
9.0 KiB
C++
271 lines
9.0 KiB
C++
// Filename: wrapperBuilderPython.C
|
|
// Created by: drose (07Aug00)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "wrapperBuilderPython.h"
|
|
#include "interrogate.h"
|
|
#include "parameterRemap.h"
|
|
#include "typeManager.h"
|
|
|
|
#include <interrogateDatabase.h>
|
|
#include <cppInstance.h>
|
|
#include <cppFunctionType.h>
|
|
#include <cppParameterList.h>
|
|
#include <cppConstType.h>
|
|
#include <cppReferenceType.h>
|
|
#include <cppPointerType.h>
|
|
#include <cppSimpleType.h>
|
|
#include <cppStructType.h>
|
|
#include <cppExpression.h>
|
|
#include <notify.h>
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: WrapperBuilderPython::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
WrapperBuilderPython::
|
|
WrapperBuilderPython() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: WrapperBuilderPython::write_wrapper
|
|
// Access: Public, Virtual
|
|
// Description: Generates a wrapper function to the indicated output
|
|
// stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
void WrapperBuilderPython::
|
|
write_wrapper(ostream &out, const string &wrapper_name) const {
|
|
out << "/*\n"
|
|
<< " * Python wrapper for\n"
|
|
<< " * " << _description << "\n"
|
|
<< " */\n";
|
|
|
|
if (!output_function_names) {
|
|
// If we're not saving the function names, don't export it from
|
|
// the library.
|
|
out << "static ";
|
|
}
|
|
|
|
out << "PyObject *\n"
|
|
<< wrapper_name << "(PyObject *, PyObject *args) {\n";
|
|
|
|
write_spam_message(out);
|
|
|
|
int pn;
|
|
|
|
string format_specifiers;
|
|
string parameter_list;
|
|
vector_string pexprs;
|
|
|
|
// Make one pass through the parameter list. We will output a
|
|
// one-line temporary variable definition for each parameter, while
|
|
// simultaneously building the ParseTuple() function call and also
|
|
// the parameter expression list for call_function().
|
|
|
|
for (pn = 0; pn < (int)_parameters.size(); pn++) {
|
|
out << " ";
|
|
CPPType *orig_type = _parameters[pn]._remap->get_orig_type();
|
|
CPPType *type = _parameters[pn]._remap->get_new_type();
|
|
|
|
// This is the string to convert our local variable to the
|
|
// appropriate C++ type. Normally this is just a cast.
|
|
string pexpr_string =
|
|
"(" + type->get_local_name(&parser) + ")" + get_parameter_name(pn);
|
|
|
|
if (_parameters[pn]._remap->new_type_is_atomic_string()) {
|
|
if (TypeManager::is_char_pointer(orig_type)) {
|
|
out << "char *" << get_parameter_name(pn);
|
|
format_specifiers += "s";
|
|
parameter_list += ", &" + get_parameter_name(pn);
|
|
|
|
} else {
|
|
out << "char *" << get_parameter_name(pn)
|
|
<< "_str; int " << get_parameter_name(pn) << "_len";
|
|
format_specifiers += "s#";
|
|
parameter_list += ", &" + get_parameter_name(pn)
|
|
+ "_str, &" + get_parameter_name(pn) + "_len";
|
|
pexpr_string = "basic_string<char>(" +
|
|
get_parameter_name(pn) + "_str, " +
|
|
get_parameter_name(pn) + "_len)";
|
|
}
|
|
|
|
} else if (TypeManager::is_bool(type)) {
|
|
out << "PyObject *" << get_parameter_name(pn);
|
|
format_specifiers += "O";
|
|
parameter_list += ", &" + get_parameter_name(pn);
|
|
pexpr_string = "(PyObject_IsTrue(" + get_parameter_name(pn) + ")!=0)";
|
|
|
|
} else if (TypeManager::is_integer(type)) {
|
|
out << "int " << get_parameter_name(pn);
|
|
format_specifiers += "i";
|
|
parameter_list += ", &" + get_parameter_name(pn);
|
|
|
|
} else if (TypeManager::is_float(type)) {
|
|
out << "double " << get_parameter_name(pn);
|
|
format_specifiers += "d";
|
|
parameter_list += ", &" + get_parameter_name(pn);
|
|
|
|
} else if (TypeManager::is_char_pointer(type)) {
|
|
out << "char *" << get_parameter_name(pn);
|
|
format_specifiers += "s";
|
|
parameter_list += ", &" + get_parameter_name(pn);
|
|
|
|
} else if (TypeManager::is_pointer(type)) {
|
|
out << "int " << get_parameter_name(pn);
|
|
format_specifiers += "i";
|
|
parameter_list += ", &" + get_parameter_name(pn);
|
|
|
|
} else {
|
|
// Ignore a parameter.
|
|
out << "PyObject *" << get_parameter_name(pn);
|
|
format_specifiers += "O";
|
|
parameter_list += ", &" + get_parameter_name(pn);
|
|
}
|
|
|
|
out << ";\n";
|
|
pexprs.push_back(pexpr_string);
|
|
}
|
|
|
|
out << " if (PyArg_ParseTuple(args, \"" << format_specifiers
|
|
<< "\"" << parameter_list << ")) {\n";
|
|
|
|
if (_return_type->new_type_is_atomic_string()) {
|
|
// Treat strings as a special case. We don't want to format the
|
|
// return expression.
|
|
string return_expr = call_function(out, 4, false, pexprs);
|
|
|
|
CPPType *type = _return_type->get_orig_type();
|
|
out << " ";
|
|
type->output_instance(out, "return_value", &parser);
|
|
out << " = " << return_expr << ";\n";
|
|
return_expr = manage_return_value(out, 4, "return_value");
|
|
test_assert(out, 4);
|
|
pack_return_value(out, return_expr);
|
|
|
|
} else {
|
|
string return_expr = call_function(out, 4, true, pexprs);
|
|
if (return_expr.empty()) {
|
|
test_assert(out, 4);
|
|
out << " return Py_BuildValue(\"\");\n";
|
|
|
|
} else {
|
|
CPPType *type = _return_type->get_temporary_type();
|
|
out << " ";
|
|
type->output_instance(out, "return_value", &parser);
|
|
out << " = " << return_expr << ";\n";
|
|
|
|
return_expr = manage_return_value(out, 4, "return_value");
|
|
test_assert(out, 4);
|
|
pack_return_value(out, _return_type->temporary_to_return(return_expr));
|
|
}
|
|
}
|
|
|
|
out << " }\n";
|
|
|
|
out << " return (PyObject *)NULL;\n";
|
|
out << "}\n\n";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: WrapperBuilderPython::get_wrapper_name
|
|
// Access: Public, Virtual
|
|
// Description: Returns the callable name for this wrapper function.
|
|
////////////////////////////////////////////////////////////////////
|
|
string WrapperBuilderPython::
|
|
get_wrapper_name(const string &library_hash_name) const {
|
|
return "_inP" + library_hash_name + _hash;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: WrapperBuilderPython::supports_atomic_strings
|
|
// Access: Public, Virtual
|
|
// Description: Returns true if this kind of wrapper can support true
|
|
// atomic string objects (and not have to fiddle with
|
|
// char *).
|
|
////////////////////////////////////////////////////////////////////
|
|
bool WrapperBuilderPython::
|
|
supports_atomic_strings() const {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: WrapperBuilderPython::get_calling_convention
|
|
// Access: Public, Virtual
|
|
// Description: Returns an indication of what kind of function we are
|
|
// building.
|
|
////////////////////////////////////////////////////////////////////
|
|
WrapperBuilder::CallingConvention WrapperBuilderPython::
|
|
get_calling_convention() const {
|
|
return CC_python;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: WrapperBuilderPython::test_assert
|
|
// Access: Protected
|
|
// Description: Outputs code to check to see if an assertion has
|
|
// failed while the C++ code was executing, and report
|
|
// this failure back to Python.
|
|
////////////////////////////////////////////////////////////////////
|
|
void WrapperBuilderPython::
|
|
test_assert(ostream &out, int indent_level) const {
|
|
if (watch_asserts) {
|
|
out << "#ifndef NDEBUG\n";
|
|
indent(out, indent_level)
|
|
<< "Notify *notify = Notify::ptr();\n";
|
|
indent(out, indent_level)
|
|
<< "if (notify->has_assert_failed()) {\n";
|
|
indent(out, indent_level + 2)
|
|
<< "PyErr_SetString(PyExc_AssertionError, notify->get_assert_error_message().c_str());\n";
|
|
indent(out, indent_level + 2)
|
|
<< "notify->clear_assert_failed();\n";
|
|
indent(out, indent_level + 2)
|
|
<< "return (PyObject *)NULL;\n";
|
|
indent(out, indent_level)
|
|
<< "}\n";
|
|
out << "#endif\n";
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: WrapperBuilderPython::pack_return_value
|
|
// Access: Protected
|
|
// Description: Outputs a command to pack the indicated expression,
|
|
// of the return_type type, as a Python return value.
|
|
////////////////////////////////////////////////////////////////////
|
|
void WrapperBuilderPython::
|
|
pack_return_value(ostream &out, string return_expr) const {
|
|
CPPType *orig_type = _return_type->get_orig_type();
|
|
CPPType *type = _return_type->get_new_type();
|
|
|
|
out << " return Py_BuildValue(";
|
|
|
|
if (_return_type->new_type_is_atomic_string()) {
|
|
if (TypeManager::is_char_pointer(orig_type)) {
|
|
out << "\"s\", " << return_expr;
|
|
|
|
} else {
|
|
out << "\"s#\", " << return_expr << ".data(), "
|
|
<< return_expr << ".length()";
|
|
}
|
|
|
|
} else if (TypeManager::is_integer(type)) {
|
|
out << "\"i\", (int)(" << return_expr << ")";
|
|
|
|
} else if (TypeManager::is_float(type)) {
|
|
out << "\"d\", (double)(" << return_expr << ")";
|
|
|
|
} else if (TypeManager::is_char_pointer(type)) {
|
|
out << "\"s\", " << return_expr;
|
|
|
|
} else if (TypeManager::is_pointer(type)) {
|
|
out << "\"i\", (int)" << return_expr;
|
|
|
|
} else {
|
|
// Return None.
|
|
out << "\"\"";
|
|
}
|
|
out << ");\n";
|
|
}
|