509 lines
18 KiB
C++
509 lines
18 KiB
C++
// Filename: interfaceMakerPythonSimple.cxx
|
|
// Created by: drose (01Oct01)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "interfaceMakerPythonSimple.h"
|
|
#include "interrogateBuilder.h"
|
|
#include "interrogate.h"
|
|
#include "functionRemap.h"
|
|
#include "parameterRemapUnchanged.h"
|
|
#include "typeManager.h"
|
|
|
|
#include "interrogateDatabase.h"
|
|
#include "interrogateType.h"
|
|
#include "interrogateFunction.h"
|
|
#include "cppFunctionType.h"
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
InterfaceMakerPythonSimple::
|
|
InterfaceMakerPythonSimple(InterrogateModuleDef *def) :
|
|
InterfaceMakerPython(def)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::Destructor
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
InterfaceMakerPythonSimple::
|
|
~InterfaceMakerPythonSimple() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::write_prototypes
|
|
// Access: Public, Virtual
|
|
// Description: Generates the list of function prototypes
|
|
// corresponding to the functions that will be output in
|
|
// write_functions().
|
|
////////////////////////////////////////////////////////////////////
|
|
void InterfaceMakerPythonSimple::
|
|
write_prototypes(ostream &out,ostream *out_h) {
|
|
Functions::iterator fi;
|
|
for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
|
|
Function *func = (*fi);
|
|
write_prototype_for(out, func);
|
|
}
|
|
|
|
out << "\n";
|
|
InterfaceMakerPython::write_prototypes(out,out_h);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::write_functions
|
|
// Access: Public, Virtual
|
|
// Description: Generates the list of functions that are appropriate
|
|
// for this interface. This function is called *before*
|
|
// write_prototypes(), above.
|
|
////////////////////////////////////////////////////////////////////
|
|
void InterfaceMakerPythonSimple::
|
|
write_functions(ostream &out) {
|
|
Functions::iterator fi;
|
|
for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
|
|
Function *func = (*fi);
|
|
write_function_for(out, func);
|
|
}
|
|
|
|
InterfaceMakerPython::write_functions(out);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::write_module
|
|
// Access: Public, Virtual
|
|
// Description: Generates whatever additional code is required to
|
|
// support a module file.
|
|
////////////////////////////////////////////////////////////////////
|
|
void InterfaceMakerPythonSimple::
|
|
write_module(ostream &out,ostream *out_h, InterrogateModuleDef *def) {
|
|
InterfaceMakerPython::write_module(out,out_h, def);
|
|
|
|
out << "static PyMethodDef python_simple_funcs[] = {\n";
|
|
|
|
Functions::iterator fi;
|
|
for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
|
|
Function *func = (*fi);
|
|
Function::Remaps::const_iterator ri;
|
|
for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
|
|
FunctionRemap *remap = (*ri);
|
|
out << " { \"" << remap->_reported_name << "\", &"
|
|
<< remap->_wrapper_name << ", METH_VARARGS },\n";
|
|
}
|
|
}
|
|
out << " { NULL, NULL }\n"
|
|
<< "};\n\n"
|
|
|
|
<< "#ifdef _WIN32\n"
|
|
<< "extern \"C\" __declspec(dllexport) void init" << def->library_name << "();\n"
|
|
<< "#else\n"
|
|
<< "extern \"C\" void init" << def->library_name << "();\n"
|
|
<< "#endif\n\n"
|
|
|
|
<< "void init" << def->library_name << "() {\n"
|
|
<< " Py_InitModule(\"" << def->library_name
|
|
<< "\", python_simple_funcs);\n"
|
|
<< "}\n\n";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::synthesize_this_parameter
|
|
// Access: Public, Virtual
|
|
// Description: This method should be overridden and redefined to
|
|
// return true for interfaces that require the implicit
|
|
// "this" parameter, if present, to be passed as the
|
|
// first parameter to any wrapper functions.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool InterfaceMakerPythonSimple::
|
|
synthesize_this_parameter() {
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::get_wrapper_prefix
|
|
// Access: Protected, Virtual
|
|
// Description: Returns the prefix string used to generate wrapper
|
|
// function names.
|
|
////////////////////////////////////////////////////////////////////
|
|
string InterfaceMakerPythonSimple::
|
|
get_wrapper_prefix() {
|
|
return "_inP";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::get_unique_prefix
|
|
// Access: Protected, Virtual
|
|
// Description: Returns the prefix string used to generate unique
|
|
// symbolic names, which are not necessarily C-callable
|
|
// function names.
|
|
////////////////////////////////////////////////////////////////////
|
|
string InterfaceMakerPythonSimple::
|
|
get_unique_prefix() {
|
|
return "p";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::record_function_wrapper
|
|
// Access: Protected, Virtual
|
|
// Description: Associates the function wrapper with its function in
|
|
// the appropriate structures in the database.
|
|
////////////////////////////////////////////////////////////////////
|
|
void InterfaceMakerPythonSimple::
|
|
record_function_wrapper(InterrogateFunction &ifunc,
|
|
FunctionWrapperIndex wrapper_index) {
|
|
ifunc._python_wrappers.push_back(wrapper_index);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::write_prototype_for
|
|
// Access: Private
|
|
// Description: Writes the prototype for the indicated function.
|
|
////////////////////////////////////////////////////////////////////
|
|
void InterfaceMakerPythonSimple::
|
|
write_prototype_for(ostream &out, InterfaceMaker::Function *func) {
|
|
Function::Remaps::const_iterator ri;
|
|
|
|
for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
|
|
FunctionRemap *remap = (*ri);
|
|
if (!output_function_names) {
|
|
// If we're not saving the function names, don't export it from
|
|
// the library.
|
|
out << "static ";
|
|
} else {
|
|
out << "extern \"C\" ";
|
|
}
|
|
out << "PyObject *"
|
|
<< remap->_wrapper_name << "(PyObject *self, PyObject *args);\n";
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::write_function_for
|
|
// Access: Private
|
|
// Description: Writes the definition for a function that will call
|
|
// the indicated C++ function or method.
|
|
////////////////////////////////////////////////////////////////////
|
|
void InterfaceMakerPythonSimple::
|
|
write_function_for(ostream &out, InterfaceMaker::Function *func) {
|
|
Function::Remaps::const_iterator ri;
|
|
|
|
for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
|
|
FunctionRemap *remap = (*ri);
|
|
write_function_instance(out, func, remap);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::write_function_instance
|
|
// Access: Private
|
|
// Description: Writes out the particular function that handles a
|
|
// single instance of an overloaded function.
|
|
////////////////////////////////////////////////////////////////////
|
|
void InterfaceMakerPythonSimple::write_function_instance(ostream &out, InterfaceMaker::Function *func,
|
|
FunctionRemap *remap) {
|
|
out << "/*\n"
|
|
<< " * Python simple wrapper for\n"
|
|
<< " * ";
|
|
remap->write_orig_prototype(out, 0);
|
|
out << "\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"
|
|
<< remap->_wrapper_name << "(PyObject *, PyObject *args) {\n";
|
|
|
|
if (generate_spam) {
|
|
write_spam_message(out, remap);
|
|
}
|
|
|
|
string format_specifiers;
|
|
string parameter_list;
|
|
string container;
|
|
vector_string pexprs;
|
|
string extra_convert;
|
|
string extra_param_check;
|
|
string extra_cleanup;
|
|
|
|
// 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().
|
|
|
|
int pn;
|
|
for (pn = 0; pn < (int)remap->_parameters.size(); ++pn) {
|
|
indent(out, 2);
|
|
CPPType *orig_type = remap->_parameters[pn]._remap->get_orig_type();
|
|
CPPType *type = remap->_parameters[pn]._remap->get_new_type();
|
|
string param_name = remap->get_parameter_name(pn);
|
|
|
|
// 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) + ")" + param_name;
|
|
|
|
if (remap->_parameters[pn]._remap->new_type_is_atomic_string()) {
|
|
if (TypeManager::is_char_pointer(orig_type)) {
|
|
out << "char *" << param_name;
|
|
format_specifiers += "s";
|
|
parameter_list += ", &" + param_name;
|
|
|
|
} else if (TypeManager::is_wstring(orig_type)) {
|
|
out << "Py_UNICODE *" << param_name
|
|
<< "_str; int " << param_name << "_len";
|
|
format_specifiers += "u#";
|
|
parameter_list += ", &" + param_name
|
|
+ "_str, &" + param_name + "_len";
|
|
pexpr_string = "basic_string<wchar_t>((wchar_t *)" +
|
|
param_name + "_str, " +
|
|
param_name + "_len)";
|
|
|
|
} else {
|
|
out << "char *" << param_name
|
|
<< "_str; int " << param_name << "_len";
|
|
format_specifiers += "s#";
|
|
parameter_list += ", &" + param_name
|
|
+ "_str, &" + param_name + "_len";
|
|
pexpr_string = "basic_string<char>(" +
|
|
param_name + "_str, " +
|
|
param_name + "_len)";
|
|
}
|
|
|
|
} else if (TypeManager::is_bool(type)) {
|
|
out << "PyObject *" << param_name;
|
|
format_specifiers += "O";
|
|
parameter_list += ", &" + param_name;
|
|
pexpr_string = "(PyObject_IsTrue(" + param_name + ")!=0)";
|
|
|
|
} else if (TypeManager::is_unsigned_longlong(type)) {
|
|
out << "PyObject *" << param_name;
|
|
format_specifiers += "O";
|
|
parameter_list += ", &" + param_name;
|
|
extra_convert += " PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");";
|
|
extra_param_check += "|| (" + param_name + "_long == NULL)";
|
|
pexpr_string = "PyLong_AsUnsignedLongLong(" + param_name + "_long)";
|
|
extra_cleanup += " Py_XDECREF(" + param_name + "_long);";
|
|
|
|
} else if (TypeManager::is_longlong(type)) {
|
|
out << "PyObject *" << param_name;
|
|
format_specifiers += "O";
|
|
parameter_list += ", &" + param_name;
|
|
extra_convert += " PyObject *" + param_name + "_long = PyNumber_Long(" + param_name + ");";
|
|
extra_param_check += "|| (" + param_name + "_long == NULL)";
|
|
pexpr_string = "PyLong_AsLongLong(" + param_name + "_long)";
|
|
extra_cleanup += " Py_XDECREF(" + param_name + "_long);";
|
|
|
|
} else if (TypeManager::is_unsigned_integer(type)) {
|
|
out << "PyObject *" << param_name;
|
|
format_specifiers += "O";
|
|
parameter_list += ", &" + param_name;
|
|
extra_convert += " PyObject *" + param_name + "_uint = PyNumber_Long(" + param_name + ");";
|
|
extra_param_check += "|| (" + param_name + "_uint == NULL)";
|
|
pexpr_string = "(unsigned int)PyLong_AsUnsignedLong(" + param_name + "_uint)";
|
|
extra_cleanup += " Py_XDECREF(" + param_name + "_uint);";
|
|
|
|
} else if (TypeManager::is_integer(type)) {
|
|
out << "int " << param_name;
|
|
format_specifiers += "i";
|
|
parameter_list += ", &" + param_name;
|
|
|
|
} else if (TypeManager::is_float(type)) {
|
|
out << "double " << param_name;
|
|
format_specifiers += "d";
|
|
parameter_list += ", &" + param_name;
|
|
|
|
} else if (TypeManager::is_char_pointer(type)) {
|
|
out << "char *" << param_name;
|
|
format_specifiers += "s";
|
|
parameter_list += ", &" + param_name;
|
|
|
|
} else if (TypeManager::is_pointer_to_PyObject(type)) {
|
|
out << "PyObject *" << param_name;
|
|
format_specifiers += "O";
|
|
parameter_list += ", &" + param_name;
|
|
pexpr_string = param_name;
|
|
|
|
} else if (TypeManager::is_pointer(type)) {
|
|
out << "int " << param_name;
|
|
format_specifiers += "i";
|
|
parameter_list += ", &" + param_name;
|
|
|
|
} else {
|
|
// Ignore a parameter.
|
|
out << "PyObject *" << param_name;
|
|
format_specifiers += "O";
|
|
parameter_list += ", &" + param_name;
|
|
}
|
|
|
|
out << ";\n";
|
|
if (remap->_has_this && pn == 0) {
|
|
// The "this" parameter gets passed in separately.
|
|
container = pexpr_string;
|
|
}
|
|
pexprs.push_back(pexpr_string);
|
|
}
|
|
|
|
out << " if (PyArg_ParseTuple(args, \"" << format_specifiers
|
|
<< "\"" << parameter_list << ")) {\n";
|
|
|
|
if (!extra_convert.empty()) {
|
|
out << " " << extra_convert << "\n";
|
|
}
|
|
|
|
if (!extra_param_check.empty()) {
|
|
out << " if (" << extra_param_check.substr(3) << ") {\n";
|
|
if (!extra_cleanup.empty()) {
|
|
out << " " << extra_cleanup << "\n";
|
|
}
|
|
out << " PyErr_SetString(PyExc_TypeError, \"Invalid parameters.\");\n"
|
|
<< " return (PyObject *)NULL;\n"
|
|
<< " }\n";
|
|
}
|
|
|
|
if (track_interpreter) {
|
|
out << " in_interpreter = 0;\n";
|
|
}
|
|
|
|
if (!remap->_void_return &&
|
|
remap->_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 = remap->call_function(out, 4, false, container, pexprs);
|
|
CPPType *type = remap->_return_type->get_orig_type();
|
|
out << " ";
|
|
type->output_instance(out, "return_value", &parser);
|
|
out << " = " << return_expr << ";\n";
|
|
|
|
if (track_interpreter) {
|
|
out << " in_interpreter = 1;\n";
|
|
}
|
|
if (!extra_cleanup.empty()) {
|
|
out << " " << extra_cleanup << "\n";
|
|
}
|
|
|
|
return_expr = manage_return_value(out, 4, remap, "return_value");
|
|
test_assert(out, 4);
|
|
pack_return_value(out, 4, remap, return_expr);
|
|
|
|
} else {
|
|
string return_expr = remap->call_function(out, 4, true, container, pexprs);
|
|
if (return_expr.empty()) {
|
|
if (track_interpreter) {
|
|
out << " in_interpreter = 1;\n";
|
|
}
|
|
if (!extra_cleanup.empty()) {
|
|
out << " " << extra_cleanup << "\n";
|
|
}
|
|
test_assert(out, 4);
|
|
out << " return Py_BuildValue(\"\");\n";
|
|
|
|
} else {
|
|
CPPType *type = remap->_return_type->get_temporary_type();
|
|
out << " ";
|
|
type->output_instance(out, "return_value", &parser);
|
|
out << " = " << return_expr << ";\n";
|
|
if (track_interpreter) {
|
|
out << " in_interpreter = 1;\n";
|
|
}
|
|
if (!extra_cleanup.empty()) {
|
|
out << " " << extra_cleanup << "\n";
|
|
}
|
|
|
|
return_expr = manage_return_value(out, 4, remap, "return_value");
|
|
test_assert(out, 4);
|
|
pack_return_value(out, 4, remap, remap->_return_type->temporary_to_return(return_expr));
|
|
}
|
|
}
|
|
|
|
out << " }\n";
|
|
|
|
out << " return (PyObject *)NULL;\n";
|
|
out << "}\n\n";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InterfaceMakerPythonSimple::pack_return_value
|
|
// Access: Private
|
|
// Description: Outputs a command to pack the indicated expression,
|
|
// of the return_type type, as a Python return value.
|
|
////////////////////////////////////////////////////////////////////
|
|
void InterfaceMakerPythonSimple::
|
|
pack_return_value(ostream &out, int indent_level,
|
|
FunctionRemap *remap, string return_expr) {
|
|
CPPType *orig_type = remap->_return_type->get_orig_type();
|
|
CPPType *type = remap->_return_type->get_new_type();
|
|
|
|
if (remap->_return_type->new_type_is_atomic_string())
|
|
{
|
|
if (TypeManager::is_char_pointer(orig_type)) {
|
|
indent(out, indent_level)
|
|
<< "return PyString_FromString(" << return_expr << ");\n";
|
|
|
|
} else if (TypeManager::is_wstring(orig_type)) {
|
|
indent(out, indent_level)
|
|
<< "return PyUnicode_FromWideChar("
|
|
<< return_expr << ".data(), (int)" << return_expr << ".length());\n";
|
|
|
|
} else {
|
|
indent(out, indent_level)
|
|
<< "return PyString_FromStringAndSize("
|
|
<< return_expr << ".data(), " << return_expr << ".length());\n";
|
|
}
|
|
|
|
} else if (TypeManager::is_unsigned_longlong(type))
|
|
{
|
|
indent(out, indent_level)
|
|
<< "return PyLong_FromUnsignedLongLong(" << return_expr << ");\n";
|
|
|
|
} else if (TypeManager::is_longlong(type))
|
|
{
|
|
indent(out, indent_level)
|
|
<< "return PyLong_FromLongLong(" << return_expr << ");\n";
|
|
|
|
} else if (TypeManager::is_unsigned_integer(type)) {
|
|
indent(out, indent_level)
|
|
<< "return PyLong_FromUnsignedLong(" << return_expr << ");\n";
|
|
|
|
} else if (TypeManager::is_integer(type)) {
|
|
indent(out, indent_level)
|
|
<< "return PyInt_FromLong(" << return_expr << ");\n";
|
|
|
|
} else if (TypeManager::is_float(type)) {
|
|
indent(out, indent_level)
|
|
<< "return PyFloat_FromDouble(" << return_expr << ");\n";
|
|
|
|
} else if (TypeManager::is_char_pointer(type)) {
|
|
indent(out, indent_level)
|
|
<< "return PyString_FromString(" << return_expr << ");\n";
|
|
|
|
} else if (TypeManager::is_pointer_to_PyObject(type)) {
|
|
indent(out, indent_level)
|
|
<< "return " << return_expr << ";\n";
|
|
|
|
} else if (TypeManager::is_pointer(type)) {
|
|
indent(out, indent_level)
|
|
<< "return PyInt_FromLong((int)" << return_expr << ");\n";
|
|
|
|
} else {
|
|
// Return None.
|
|
indent(out, indent_level)
|
|
<< "return Py_BuildValue(\"\");\n";
|
|
}
|
|
}
|