Improve interrogate code readability, use METH_STATIC for static methods, support anonymous enums

This commit is contained in:
rdb 2014-07-22 20:06:59 +00:00
parent e98618b105
commit f02662d4e0
7 changed files with 265 additions and 231 deletions

View File

@ -50,6 +50,7 @@ FunctionRemap(const InterrogateType &itype, const InterrogateFunction &ifunc,
_num_default_parameters = num_default_parameters; _num_default_parameters = num_default_parameters;
_type = T_normal; _type = T_normal;
_flags = 0; _flags = 0;
_args_type = 0;
_wrapper_index = 0; _wrapper_index = 0;
_return_value_needs_management = false; _return_value_needs_management = false;
@ -648,11 +649,11 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
} }
if (_parameters.size() == first_param) { if (_parameters.size() == first_param) {
_flags |= F_no_args; _args_type = InterfaceMaker::AT_no_args;
} else if (_parameters.size() == first_param + 1) { } else if (_parameters.size() == first_param + 1) {
_flags |= F_single_arg; _args_type = InterfaceMaker::AT_single_arg;
} else { } else {
_flags |= F_varargs; _args_type = InterfaceMaker::AT_varargs;
} }
if (_type == T_normal) { if (_type == T_normal) {
@ -670,7 +671,8 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
if (_has_this && _parameters.size() > 2) { if (_has_this && _parameters.size() > 2) {
if (TypeManager::is_integer(_parameters[1]._remap->get_new_type())) { if (TypeManager::is_integer(_parameters[1]._remap->get_new_type())) {
// Its first parameter is an int parameter, presumably an index. // Its first parameter is an int parameter, presumably an index.
_flags |= (F_setitem_int | F_varargs); _flags |= F_setitem_int;
_args_type = InterfaceMaker::AT_varargs;
} }
} }
@ -720,16 +722,16 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
} else if (fname == "operator ()" || fname == "__call__") { } else if (fname == "operator ()" || fname == "__call__") {
// Call operators always take keyword arguments. // Call operators always take keyword arguments.
_flags |= (F_varargs | F_keyword_args); _args_type = InterfaceMaker::AT_keyword_args;
} else if (fname == "__setattr__" || fname == "__getattr__") { } else if (fname == "__setattr__" || fname == "__getattr__") {
// Just to prevent these from getting keyword arguments. // Just to prevent these from getting keyword arguments.
} else { } else {
if (_flags & F_varargs) { if (_args_type == InterfaceMaker::AT_varargs) {
// Every other method can take keyword arguments, if they // Every other method can take keyword arguments, if they
// take more than one argument. // take more than one argument.
_flags |= F_keyword_args; _args_type = InterfaceMaker::AT_keyword_args;
} }
} }
@ -743,7 +745,7 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
} }
// Constructors always take varargs and keyword args. // Constructors always take varargs and keyword args.
_flags |= (F_varargs | F_keyword_args); _args_type = InterfaceMaker::AT_keyword_args;
} }
return true; return true;

View File

@ -91,10 +91,6 @@ public:
F_getbuffer = 0x0200, F_getbuffer = 0x0200,
F_releasebuffer = 0x0400, F_releasebuffer = 0x0400,
F_compare_to = 0x0800, F_compare_to = 0x0800,
F_no_args = 0x1000,
F_single_arg = 0x2000,
F_varargs = 0x4000,
F_keyword_args = 0x8000,
}; };
typedef vector<Parameter> Parameters; typedef vector<Parameter> Parameters;
@ -111,6 +107,7 @@ public:
int _num_default_parameters; int _num_default_parameters;
Type _type; Type _type;
int _flags; int _flags;
int _args_type;
string _expression; string _expression;
string _function_signature; string _function_signature;
string _hash; string _hash;

View File

@ -57,6 +57,7 @@ Function(const string &name,
{ {
_has_this = false; _has_this = false;
_flags = 0; _flags = 0;
_args_type = AT_unknown;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -632,13 +633,13 @@ record_function(const InterrogateType &itype, FunctionIndex func_index) {
CPPInstance *cppfunc = (*ii).second; CPPInstance *cppfunc = (*ii).second;
CPPFunctionType *ftype = cppfunc->_type->as_function_type(); CPPFunctionType *ftype = cppfunc->_type->as_function_type();
int max_default_parameters = 0; int max_default_parameters = 0;
if (separate_overloading()) { if (separate_overloading()) {
// Count up the number of default parameters this function might // Count up the number of default parameters this function might
// take. // take.
CPPParameterList *parameters = ftype->_parameters; CPPParameterList *parameters = ftype->_parameters;
CPPParameterList::Parameters::reverse_iterator pi; CPPParameterList::Parameters::reverse_iterator pi;
for (pi = parameters->_parameters.rbegin(); for (pi = parameters->_parameters.rbegin();
pi != parameters->_parameters.rend(); pi != parameters->_parameters.rend();
++pi) { ++pi) {
CPPInstance *param = (*pi); CPPInstance *param = (*pi);
@ -651,7 +652,7 @@ record_function(const InterrogateType &itype, FunctionIndex func_index) {
} }
} }
} }
// Now make a different wrapper for each combination of default // Now make a different wrapper for each combination of default
// parameters. This will happen only if separate_overloading(), // parameters. This will happen only if separate_overloading(),
// tested above, returned true; otherwise, max_default_parameters // tested above, returned true; otherwise, max_default_parameters
@ -672,9 +673,10 @@ record_function(const InterrogateType &itype, FunctionIndex func_index) {
} }
func->_flags |= remap->_flags; func->_flags |= remap->_flags;
func->_args_type = (ArgsType)((int)func->_args_type | (int)remap->_args_type);
// Make a wrapper for the function. // Make a wrapper for the function.
FunctionWrapperIndex wrapper_index = FunctionWrapperIndex wrapper_index =
remap->make_wrapper_entry(func_index); remap->make_wrapper_entry(func_index);
if (wrapper_index != 0) { if (wrapper_index != 0) {
InterrogateFunction &mod_ifunc = idb->update_function(func_index); InterrogateFunction &mod_ifunc = idb->update_function(func_index);
@ -685,13 +687,6 @@ record_function(const InterrogateType &itype, FunctionIndex func_index) {
} }
} }
// If there's a remap taking no args and a remap
// taking only a single arg, assume we need varargs.
if ((func->_flags & FunctionRemap::F_no_args) &&
(func->_flags & FunctionRemap::F_single_arg)) {
func->_flags |= FunctionRemap::F_varargs;
}
return func; return func;
} }

View File

@ -69,6 +69,28 @@ public:
static ostream &indent(ostream &out, int indent_level); static ostream &indent(ostream &out, int indent_level);
public: public:
// This contains information about the number
// of arguments that the wrapping function should take.
enum ArgsType {
// This is deliberately engineered such that these
// values can be OR'ed together to produce another
// valid enum value.
AT_unknown = 0x00,
// The method or function takes no arguments.
AT_no_args = 0x01,
// There is only a single argument.
AT_single_arg = 0x02,
// The method takes a variable number of arguments.
AT_varargs = 0x03,
// The method may take keyword arguments, if appropriate
// in the scripting language. Implies AT_varargs.
AT_keyword_args = 0x07,
};
class Function { class Function {
public: public:
Function(const string &name, Function(const string &name,
@ -83,6 +105,7 @@ public:
Remaps _remaps; Remaps _remaps;
bool _has_this; bool _has_this;
int _flags; int _flags;
ArgsType _args_type;
}; };
typedef vector<Function *> Functions; typedef vector<Function *> Functions;
Functions _functions; Functions _functions;

View File

@ -821,7 +821,7 @@ write_functions(ostream &out) {
for (fi = _functions.begin(); fi != _functions.end(); ++fi) { for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
Function *func = (*fi); Function *func = (*fi);
if (!func->_itype.is_global() && is_function_legal(func)) { if (!func->_itype.is_global() && is_function_legal(func)) {
write_function_for_top(out, NULL, func, ""); write_function_for_top(out, NULL, func);
} }
} }
@ -872,29 +872,7 @@ write_class_details(ostream &out, Object *obj) {
for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi) { for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi) {
Function *func = (*fi); Function *func = (*fi);
if (func) { if (func) {
SlottedFunctionDef def; write_function_for_top(out, obj, func);
get_slotted_function_def(obj, func, def);
ostringstream GetThis;
GetThis << " " << cClassName << " *local_this = NULL;\n";
GetThis << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n";
GetThis << " if (local_this == NULL) {\n";
if (def._wrapper_type == WT_numeric_operator || def._wrapper_type == WT_ternary_operator) {
// WT_numeric_operator means we must return NotImplemented, instead
// of raising an exception, if the this pointer doesn't
// match. This is for things like __sub__, which Python
// likes to call on the wrong-type objects.
GetThis << " Py_INCREF(Py_NotImplemented);\n";
GetThis << " return Py_NotImplemented;\n";
} else {
// Other functions should raise an exception if the this
// pointer isn't set or is the wrong type.
GetThis << " PyErr_SetString(PyExc_AttributeError, \"C++ object is not yet constructed, or already destructed.\");\n";
GetThis << " return NULL;\n";
}
GetThis << " }\n";
write_function_for_top(out, obj, func, GetThis.str());
} }
} }
@ -915,7 +893,7 @@ write_class_details(ostream &out, Object *obj) {
Function *func = (*fi); Function *func = (*fi);
std::string fname = "int Dtool_Init_" + ClassName + "(PyObject *self, PyObject *args, PyObject *kwds)"; std::string fname = "int Dtool_Init_" + ClassName + "(PyObject *self, PyObject *args, PyObject *kwds)";
write_function_for_name(out, obj, func, fname, "", true, coercion_attempted, false, true, true, true); write_function_for_name(out, obj, func, fname, true, coercion_attempted, AT_keyword_args, true);
} }
if (coercion_attempted) { if (coercion_attempted) {
// If a coercion attempt was written into the above constructor, // If a coercion attempt was written into the above constructor,
@ -925,7 +903,7 @@ write_class_details(ostream &out, Object *obj) {
Function *func = (*fi); Function *func = (*fi);
std::string fname = "int Dtool_InitNoCoerce_" + ClassName + "(PyObject *self, PyObject *args)"; std::string fname = "int Dtool_InitNoCoerce_" + ClassName + "(PyObject *self, PyObject *args)";
write_function_for_name(out, obj, func, fname, "", false, coercion_attempted, false, true, false, true); write_function_for_name(out, obj, func, fname, false, coercion_attempted, AT_varargs, true);
} }
} else { } else {
// Otherwise, since the above constructor didn't involve any // Otherwise, since the above constructor didn't involve any
@ -1143,17 +1121,28 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
string name1 = methodNameFromCppName(func, "", false); string name1 = methodNameFromCppName(func, "", false);
string name2 = methodNameFromCppName(func, "", true); string name2 = methodNameFromCppName(func, "", true);
const char *flags; string flags;
if (func->_flags & FunctionRemap::F_keyword_args) { switch (func->_args_type) {
case AT_keyword_args:
flags = "METH_VARARGS | METH_KEYWORDS"; flags = "METH_VARARGS | METH_KEYWORDS";
} else if (func->_flags & FunctionRemap::F_varargs) { break;
case AT_varargs:
flags = "METH_VARARGS"; flags = "METH_VARARGS";
} else if (func->_flags & FunctionRemap::F_single_arg) { break;
case AT_single_arg:
flags = "METH_O"; flags = "METH_O";
} else { break;
default:
flags = "METH_NOARGS"; flags = "METH_NOARGS";
break;
} }
// Note: we shouldn't add METH_STATIC here, since both METH_STATIC
// and METH_CLASS are illegal for module-level functions.
out << " { \"" << name1 << "\", (PyCFunction) &" out << " { \"" << name1 << "\", (PyCFunction) &"
<< func->_name << ", " << flags << ", (const char *)" << func->_name << "_comment},\n"; << func->_name << ", " << flags << ", (const char *)" << func->_name << "_comment},\n";
if (name1 != name2) { if (name1 != name2) {
@ -1261,13 +1250,12 @@ write_module_class(ostream &out, Object *obj) {
out << "//********************************************************************\n"; out << "//********************************************************************\n";
out << "PyMethodDef Dtool_Methods_" << ClassName << "[] = {\n"; out << "PyMethodDef Dtool_Methods_" << ClassName << "[] = {\n";
std::map<int, Function *> static_functions;
std::map<Function *, SlottedFunctionDef> slotted_functions; std::map<Function *, SlottedFunctionDef> slotted_functions;
// function Table // function Table
bool got_copy = false; bool got_copy = false;
bool got_deepcopy = false; bool got_deepcopy = false;
int x = 0; //int x = 0;
for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi) { for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi) {
Function *func = (*fi); Function *func = (*fi);
if (func->_name == "__copy__") { if (func->_name == "__copy__") {
@ -1276,33 +1264,39 @@ write_module_class(ostream &out, Object *obj) {
got_deepcopy = true; got_deepcopy = true;
} }
if (!isFunctionWithThis(func)) {
// Save a reference to this static method, so we can add it
// directly to the class.
static_functions[x] = func;
}
string name1 = methodNameFromCppName(func, export_class_name, false); string name1 = methodNameFromCppName(func, export_class_name, false);
string name2 = methodNameFromCppName(func, export_class_name, true); string name2 = methodNameFromCppName(func, export_class_name, true);
const char *flags; string flags;
if (func->_flags & FunctionRemap::F_keyword_args) { switch (func->_args_type) {
case AT_keyword_args:
flags = "METH_VARARGS | METH_KEYWORDS"; flags = "METH_VARARGS | METH_KEYWORDS";
} else if (func->_flags & FunctionRemap::F_varargs) { break;
case AT_varargs:
flags = "METH_VARARGS"; flags = "METH_VARARGS";
} else if (func->_flags & FunctionRemap::F_single_arg) { break;
case AT_single_arg:
flags = "METH_O"; flags = "METH_O";
} else { break;
default:
flags = "METH_NOARGS"; flags = "METH_NOARGS";
break;
}
if (!func->_has_this) {
flags += " | METH_STATIC";
} }
out << " { \"" << name1 << "\", (PyCFunction) &" out << " { \"" << name1 << "\", (PyCFunction) &"
<< func->_name << ", " << flags << ", (char *) " << func->_name << "_comment},\n"; << func->_name << ", " << flags << ", (char *) " << func->_name << "_comment},\n";
++x; //++x;
if (name1 != name2) { if (name1 != name2) {
out << " { \"" << name2 << "\", (PyCFunction) &" out << " { \"" << name2 << "\", (PyCFunction) &"
<< func->_name << ", " << flags << ", (char *) " << func->_name << "_comment},\n"; << func->_name << ", " << flags << ", (char *) " << func->_name << "_comment},\n";
++x; //++x;
} }
SlottedFunctionDef slotted_def; SlottedFunctionDef slotted_def;
@ -1384,17 +1378,21 @@ write_module_class(ostream &out, Object *obj) {
bool func_varargs = true; bool func_varargs = true;
string call_func; string call_func;
if (func->_flags & FunctionRemap::F_keyword_args) { switch (func->_args_type) {
case AT_keyword_args:
call_func = func->_name + "(self, args, NULL)"; call_func = func->_name + "(self, args, NULL)";
break;
} else if (func->_flags & FunctionRemap::F_varargs) { case AT_varargs:
call_func = func->_name + "(self, args)"; call_func = func->_name + "(self, args)";
break;
} else if (func->_flags & FunctionRemap::F_single_arg) { case AT_single_arg:
func_varargs = false; func_varargs = false;
call_func = func->_name + "(self, arg)"; call_func = func->_name + "(self, arg)";
break;
} else { default:
func_varargs = false; func_varargs = false;
call_func = func->_name + "(self)"; call_func = func->_name + "(self)";
} }
@ -1536,7 +1534,8 @@ write_module_class(ostream &out, Object *obj) {
string expected_params; string expected_params;
bool coercion_attempted = false; bool coercion_attempted = false;
write_function_forset(out, obj, func, remaps, expected_params, 2, false, false, coercion_attempted, false, false, false, false, "index"); write_function_forset(out, obj, func, remaps, expected_params, 2, false, false,
coercion_attempted, AT_no_args, false, "index");
out << " return NULL;\n"; out << " return NULL;\n";
out << "}\n\n"; out << "}\n\n";
@ -1578,7 +1577,8 @@ write_module_class(ostream &out, Object *obj) {
// very often, it's probably best to disable it for performance. // very often, it's probably best to disable it for performance.
string expected_params; string expected_params;
bool coercion_attempted = false; bool coercion_attempted = false;
write_function_forset(out, obj, func, remaps, expected_params, 2, false, false, coercion_attempted, true, false, false, true, "index"); write_function_forset(out, obj, func, remaps, expected_params, 2, false, false,
coercion_attempted, AT_single_arg, true, "index");
out << " if (!PyErr_Occurred()) {\n"; out << " if (!PyErr_Occurred()) {\n";
out << " PyErr_SetString(PyExc_TypeError,\n"; out << " PyErr_SetString(PyExc_TypeError,\n";
@ -1998,7 +1998,7 @@ write_module_class(ostream &out, Object *obj) {
Function::Remaps::const_iterator ri; Function::Remaps::const_iterator ri;
for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
FunctionRemap *remap = (*ri); FunctionRemap *remap = (*ri);
if (is_remap_legal(remap) && remap->_has_this && (remap->_flags & FunctionRemap::F_single_arg)) { if (is_remap_legal(remap) && remap->_has_this && (remap->_args_type == AT_single_arg)) {
remaps.insert(remap); remaps.insert(remap);
} }
} }
@ -2024,7 +2024,8 @@ write_module_class(ostream &out, Object *obj) {
string expected_params; string expected_params;
bool coercion_attempted = false; bool coercion_attempted = false;
write_function_forset(out, obj, func, remaps, expected_params, 4, false, true, coercion_attempted, true, false, false, false); write_function_forset(out, obj, func, remaps, expected_params, 4, false, true,
coercion_attempted, AT_single_arg, false);
out << " if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError)) {\n"; out << " if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_TypeError)) {\n";
out << " PyErr_Clear();\n"; out << " PyErr_Clear();\n";
@ -2213,7 +2214,14 @@ write_module_class(ostream &out, Object *obj) {
int enum_count = nested_obj->_itype.number_of_enum_values(); int enum_count = nested_obj->_itype.number_of_enum_values();
for (int xx = 0; xx < enum_count; xx++) { for (int xx = 0; xx < enum_count; xx++) {
string name1 = classNameFromCppName(nested_obj->_itype.get_enum_value_name(xx), false); string name1 = classNameFromCppName(nested_obj->_itype.get_enum_value_name(xx), false);
string name2 = classNameFromCppName(nested_obj->_itype.get_enum_value_name(xx), true); string name2;
if (nested_obj->_itype.has_true_name()) {
name2 = classNameFromCppName(nested_obj->_itype.get_enum_value_name(xx), true);
} else {
// Don't generate the alternative syntax for anonymous enums, since we added support
// for those after we started deprecating the alternative syntax.
name2 = name1;
}
int enum_value = nested_obj->_itype.get_enum_value(xx); int enum_value = nested_obj->_itype.get_enum_value(xx);
out << "#if PY_MAJOR_VERSION >= 3\n"; out << "#if PY_MAJOR_VERSION >= 3\n";
out << " PyDict_SetItemString(Dtool_" << ClassName << ".As_PyTypeObject().tp_dict, \"" << name1 << "\", PyLong_FromLong(" << enum_value << "));\n"; out << " PyDict_SetItemString(Dtool_" << ClassName << ".As_PyTypeObject().tp_dict, \"" << name1 << "\", PyLong_FromLong(" << enum_value << "));\n";
@ -2242,25 +2250,6 @@ write_module_class(ostream &out, Object *obj) {
// Why make the class a member of itself? // Why make the class a member of itself?
//out << " PyDict_SetItemString(Dtool_" <<ClassName << ".As_PyTypeObject().tp_dict,\"" <<export_class_name<< "\",&Dtool_" <<ClassName << ".As_PyObject());\n"; //out << " PyDict_SetItemString(Dtool_" <<ClassName << ".As_PyTypeObject().tp_dict,\"" <<export_class_name<< "\",&Dtool_" <<ClassName << ".As_PyObject());\n";
// static function into dictionary with bogus self..
//
std::map<int , Function * >::iterator sfi;
for (sfi = static_functions.begin(); sfi != static_functions.end(); sfi++) {
out << " // Static Method " << methodNameFromCppName(sfi->second, export_class_name, false) << "\n";
string name1 = methodNameFromCppName(sfi->second, export_class_name, false);
string name2 = methodNameFromCppName(sfi->second, export_class_name, true);
out << " PyDict_SetItemString(Dtool_" << ClassName
<< ".As_PyTypeObject().tp_dict, \"" << name1
<< "\", PyCFunction_New(&Dtool_Methods_" << ClassName << "[" << sfi->first
<< "], &Dtool_" << ClassName << ".As_PyObject()));\n";
if (name1 != name2) {
out << " PyDict_SetItemString(Dtool_" << ClassName
<< ".As_PyTypeObject().tp_dict, \"" << name2
<< "\", PyCFunction_New(&Dtool_Methods_" << ClassName << "[" << sfi->first
<< "], &Dtool_" << ClassName << ".As_PyObject()));\n";
}
}
bool is_runtime_typed = IsPandaTypedObject(obj->_itype._cpptype->as_struct_type()); bool is_runtime_typed = IsPandaTypedObject(obj->_itype._cpptype->as_struct_type());
if (HasAGetClassTypeFunction(obj->_itype)) { if (HasAGetClassTypeFunction(obj->_itype)) {
is_runtime_typed = true; is_runtime_typed = true;
@ -2379,43 +2368,37 @@ write_prototype_for_name(ostream &out, InterfaceMaker::Function *func, const std
// the indicated C++ function or method. // the indicated C++ function or method.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void InterfaceMakerPythonNative:: void InterfaceMakerPythonNative::
write_function_for_top(ostream &out, InterfaceMaker::Object *obj, InterfaceMaker::Function *func, const std::string &PreProcess) { write_function_for_top(ostream &out, InterfaceMaker::Object *obj, InterfaceMaker::Function *func) {
std::string fname; std::string fname;
bool single_arg = false;
bool have_varargs = false;
bool have_kwargs = false;
if ((func->_flags & FunctionRemap::F_keyword_args) != 0) {
// Function takes both an args tuple and a kwargs dictionary.
have_kwargs = true;
have_varargs = true;
} else if ((func->_flags & FunctionRemap::F_varargs) != 0) {
// Function takes only an args tuple.
have_varargs = true;
} else if ((func->_flags & FunctionRemap::F_single_arg) != 0) {
// Function takes a single PyObject* argument.
single_arg = true;
}
if (func->_ifunc.is_unary_op()) { if (func->_ifunc.is_unary_op()) {
assert(!single_arg); assert(func->_args_type == AT_no_args);
assert(!have_varargs);
assert(!have_kwargs);
} }
if (have_kwargs) { fname = "static PyObject *" + func->_name + "(PyObject *";
fname = "static PyObject *" + func->_name + "(PyObject *self, PyObject *args, PyObject *kwds)";
} else if (have_varargs) { // This will be NULL for static funcs, so prevent code from using it.
fname = "static PyObject *" + func->_name + "(PyObject *self, PyObject *args)"; if (func->_has_this) {
} else if (single_arg) { fname += "self";
fname = "static PyObject *" + func->_name + "(PyObject *self, PyObject *arg)";
} else {
fname = "static PyObject *" + func->_name + "(PyObject *self)";
} }
switch (func->_args_type) {
case AT_keyword_args:
fname += ", PyObject *args, PyObject *kwds";
break;
case AT_varargs:
fname += ", PyObject *args";
break;
case AT_single_arg:
fname += ", PyObject *arg";
break;
}
fname += ")";
bool coercion_attempted = false; bool coercion_attempted = false;
write_function_for_name(out, obj, func, fname, PreProcess, true, coercion_attempted, single_arg, have_varargs, have_kwargs, false); write_function_for_name(out, obj, func, fname, true, coercion_attempted, func->_args_type, false);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -2424,10 +2407,10 @@ write_function_for_top(ostream &out, InterfaceMaker::Object *obj, InterfaceMaker
// Wrap a complete name override function for Py..... // Wrap a complete name override function for Py.....
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void InterfaceMakerPythonNative:: void InterfaceMakerPythonNative::
write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMaker::Function *func, write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMaker::Function *func,
const std::string &function_name, const std::string &PreProcess, const std::string &function_name,
bool coercion_allowed, bool &coercion_attempted, bool single_arg, bool coercion_allowed, bool &coercion_attempted,
bool have_varargs, bool have_kwargs, bool return_int) { ArgsType args_type, bool return_int) {
ostringstream out; ostringstream out;
std::map<int, std::set<FunctionRemap *> > MapSets; std::map<int, std::set<FunctionRemap *> > MapSets;
@ -2458,8 +2441,33 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
out1 << " *******************************************************************/\n"; out1 << " *******************************************************************/\n";
out << function_name << " {\n"; out << function_name << " {\n";
if (isFunctionWithThis(func)) {
out << PreProcess; if (func->_has_this) {
// Extract pointer from 'self' parameter.
std::string ClassName = make_safe_name(obj->_itype.get_scoped_name());
std::string cClassName = obj->_itype.get_true_name();
SlottedFunctionDef def;
get_slotted_function_def(obj, func, def);
out << " " << cClassName << " *local_this = NULL;\n";
out << " DTOOL_Call_ExtractThisPointerForType(self, &Dtool_" << ClassName << ", (void **)&local_this);\n";
out << " if (local_this == NULL) {\n";
if (def._wrapper_type == WT_numeric_operator || def._wrapper_type == WT_ternary_operator) {
// WT_numeric_operator means we must return NotImplemented, instead
// of raising an exception, if the this pointer doesn't
// match. This is for things like __sub__, which Python
// likes to call on the wrong-type objects.
out << " Py_INCREF(Py_NotImplemented);\n";
out << " return Py_NotImplemented;\n";
} else {
// Other functions should raise an exception if the this
// pointer isn't set or is the wrong type.
out << " PyErr_SetString(PyExc_AttributeError, \"C++ object is not yet constructed, or already destructed.\");\n";
out << " return NULL;\n";
}
out << " }\n";
} }
bool is_inplace = isInplaceFunction(func); bool is_inplace = isInplaceFunction(func);
@ -2477,27 +2485,37 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
if (MapSets.size() > 1) { if (MapSets.size() > 1) {
string expected_params; string expected_params;
if (have_varargs) { switch (args_type) {
case AT_keyword_args:
indent(out, 2) << "int parameter_count = PyTuple_Size(args);\n"; indent(out, 2) << "int parameter_count = PyTuple_Size(args);\n";
if (have_kwargs) { if (args_type == AT_keyword_args) {
indent(out, 2) << "if (kwds != NULL && PyDict_Check(kwds)) {\n"; indent(out, 2) << "if (kwds != NULL && PyDict_Check(kwds)) {\n";
indent(out, 2) << " parameter_count += PyDict_Size(kwds);\n"; indent(out, 2) << " parameter_count += PyDict_Size(kwds);\n";
indent(out, 2) << "}\n"; indent(out, 2) << "}\n";
} }
break;
} else if (single_arg) { case AT_varargs:
indent(out, 2) << "int parameter_count = PyTuple_Size(args);\n";
break;
case AT_single_arg:
// It shouldń't get here, but we'll handle these cases nonetheless.
indent(out, 2) << "const int parameter_count = 1;\n"; indent(out, 2) << "const int parameter_count = 1;\n";
break;
} else { default:
indent(out, 2) << "const int parameter_count = 0;\n"; indent(out, 2) << "const int parameter_count = 0;\n";
break;
} }
indent(out, 2) << "switch (parameter_count) {\n"; indent(out, 2) << "switch (parameter_count) {\n";
for (mii = MapSets.begin(); mii != MapSets.end(); mii ++) { for (mii = MapSets.begin(); mii != MapSets.end(); mii ++) {
indent(out, 2) << "case " << mii->first << ": {\n"; indent(out, 2) << "case " << mii->first << ": {\n";
write_function_forset(out, obj, func, mii->second, expected_params, 4, is_inplace, coercion_allowed, coercion_attempted, single_arg, have_varargs, have_kwargs, return_int); write_function_forset(out, obj, func, mii->second, expected_params, 4, is_inplace,
coercion_allowed, coercion_attempted, args_type, return_int);
indent(out, 4) << "break;\n"; indent(out, 4) << "break;\n";
indent(out, 2) << "}\n"; indent(out, 2) << "}\n";
@ -2561,7 +2579,8 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
} else { } else {
string expected_params = ""; string expected_params = "";
for (mii = MapSets.begin(); mii != MapSets.end(); mii++) { for (mii = MapSets.begin(); mii != MapSets.end(); mii++) {
write_function_forset(out, obj, func, mii->second, expected_params, 2, is_inplace, coercion_allowed, coercion_attempted, single_arg, have_varargs, have_kwargs, return_int); write_function_forset(out, obj, func, mii->second, expected_params, 2, is_inplace,
coercion_allowed, coercion_attempted, args_type, return_int);
} }
out << " if (!PyErr_Occurred()) {\n"; out << " if (!PyErr_Occurred()) {\n";
@ -2712,10 +2731,9 @@ write_function_forset(ostream &out, InterfaceMaker::Object *obj,
std::set<FunctionRemap *> &remapsin, std::set<FunctionRemap *> &remapsin,
string &expected_params, int indent_level, string &expected_params, int indent_level,
bool is_inplace, bool coercion_allowed, bool is_inplace, bool coercion_allowed,
bool &coercion_attempted, bool single_arg, bool &coercion_attempted,
bool have_varargs, bool have_kwargs, ArgsType args_type,
bool return_int, bool return_int, const string &first_pexpr) {
const string &first_pexpr) {
// Do we accept any parameters that are class objects? If so, we // Do we accept any parameters that are class objects? If so, we
// might need to check for parameter coercion. // might need to check for parameter coercion.
bool coercion_possible = false; bool coercion_possible = false;
@ -2788,7 +2806,8 @@ write_function_forset(ostream &out, InterfaceMaker::Object *obj,
indent(out, indent_level) << "// -2 "; indent(out, indent_level) << "// -2 ";
remap->write_orig_prototype(out, 0); out << "\n"; remap->write_orig_prototype(out, 0); out << "\n";
write_function_instance(out, obj, func, remap, expected_params, indent_level + 2, is_inplace, coercion_possible, coercion_attempted, single_arg, have_varargs, have_kwargs, return_int, first_pexpr); write_function_instance(out, obj, func, remap, expected_params, indent_level + 2, is_inplace,
coercion_possible, coercion_attempted, args_type, return_int, first_pexpr);
indent(out, indent_level + 2) << "PyErr_Clear();\n"; indent(out, indent_level + 2) << "PyErr_Clear();\n";
indent(out, indent_level) << "}\n\n"; indent(out, indent_level) << "}\n\n";
@ -2811,7 +2830,8 @@ write_function_forset(ostream &out, InterfaceMaker::Object *obj,
<< "// 1-" ; << "// 1-" ;
remap->write_orig_prototype(out, 0); remap->write_orig_prototype(out, 0);
out << "\n" ; out << "\n" ;
write_function_instance(out, obj, func, remap, expected_params, indent_level, is_inplace, coercion_possible, coercion_attempted, single_arg, have_varargs, have_kwargs, return_int, first_pexpr); write_function_instance(out, obj, func, remap, expected_params, indent_level, is_inplace,
coercion_possible, coercion_attempted, args_type, return_int, first_pexpr);
if (remap->_has_this && !remap->_const_method) { if (remap->_has_this && !remap->_const_method) {
indent(out, indent_level - 2) indent(out, indent_level - 2)
@ -2894,8 +2914,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
FunctionRemap *remap, string &expected_params, FunctionRemap *remap, string &expected_params,
int indent_level, bool is_inplace, int indent_level, bool is_inplace,
bool coercion_possible, bool &coercion_attempted, bool coercion_possible, bool &coercion_attempted,
bool single_arg, bool have_varargs, ArgsType args_type, bool return_int,
bool have_kwargs, bool return_int,
const string &first_pexpr) { const string &first_pexpr) {
string format_specifiers; string format_specifiers;
std::string keyword_list; std::string keyword_list;
@ -3034,7 +3053,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
} else { } else {
indent(out, indent_level) << "char *" << param_name << "_str;\n"; indent(out, indent_level) << "char *" << param_name << "_str;\n";
indent(out, indent_level) << "Py_ssize_t " << param_name << "_len;\n"; indent(out, indent_level) << "Py_ssize_t " << param_name << "_len;\n";
if (single_arg) { if (args_type == AT_single_arg) {
out << "#if PY_MAJOR_VERSION >= 3\n"; out << "#if PY_MAJOR_VERSION >= 3\n";
indent(out, indent_level) indent(out, indent_level)
<< param_name << "_str = PyUnicode_AsUTF8AndSize(arg, &" << param_name << "_str = PyUnicode_AsUTF8AndSize(arg, &"
@ -3068,7 +3087,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
only_pyobjects = false; only_pyobjects = false;
} else if (TypeManager::is_bool(type)) { } else if (TypeManager::is_bool(type)) {
if (single_arg) { if (args_type == AT_single_arg) {
param_name = "arg"; param_name = "arg";
} else { } else {
indent(out, indent_level) << "PyObject *" << param_name << ";\n"; indent(out, indent_level) << "PyObject *" << param_name << ";\n";
@ -3080,7 +3099,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
++num_params; ++num_params;
} else if (TypeManager::is_unsigned_longlong(type)) { } else if (TypeManager::is_unsigned_longlong(type)) {
if (single_arg) { if (args_type == AT_single_arg) {
param_name = "arg"; param_name = "arg";
} else { } else {
indent(out, indent_level) << "PyObject *" << param_name << ";\n"; indent(out, indent_level) << "PyObject *" << param_name << ";\n";
@ -3095,7 +3114,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
++num_params; ++num_params;
} else if (TypeManager::is_longlong(type)) { } else if (TypeManager::is_longlong(type)) {
if (single_arg) { if (args_type == AT_single_arg) {
param_name = "arg"; param_name = "arg";
} else { } else {
indent(out, indent_level) << "PyObject *" << param_name << ";\n"; indent(out, indent_level) << "PyObject *" << param_name << ";\n";
@ -3110,7 +3129,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
++num_params; ++num_params;
} else if (TypeManager::is_unsigned_integer(type)) { } else if (TypeManager::is_unsigned_integer(type)) {
if (single_arg) { if (args_type == AT_single_arg) {
param_name = "arg"; param_name = "arg";
} else { } else {
indent(out, indent_level) << "PyObject *" << param_name << ";\n"; indent(out, indent_level) << "PyObject *" << param_name << ";\n";
@ -3126,7 +3145,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
++num_params; ++num_params;
} else if (TypeManager::is_integer(type)) { } else if (TypeManager::is_integer(type)) {
if (single_arg) { if (args_type == AT_single_arg) {
pexpr_string = "(" + type->get_local_name(&parser) + ")PyInt_AS_LONG(arg)"; pexpr_string = "(" + type->get_local_name(&parser) + ")PyInt_AS_LONG(arg)";
extra_param_check += " && PyInt_Check(arg)"; extra_param_check += " && PyInt_Check(arg)";
} else { } else {
@ -3139,7 +3158,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
++num_params; ++num_params;
} else if (TypeManager::is_double(type)) { } else if (TypeManager::is_double(type)) {
if (single_arg) { if (args_type == AT_single_arg) {
pexpr_string = "PyFloat_AsDouble(arg)"; pexpr_string = "PyFloat_AsDouble(arg)";
extra_param_check += " && PyNumber_Check(arg)"; extra_param_check += " && PyNumber_Check(arg)";
} else { } else {
@ -3152,7 +3171,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
++num_params; ++num_params;
} else if (TypeManager::is_float(type)) { } else if (TypeManager::is_float(type)) {
if (single_arg) { if (args_type == AT_single_arg) {
pexpr_string = "(float) PyFloat_AsDouble(arg)"; pexpr_string = "(float) PyFloat_AsDouble(arg)";
extra_param_check += " && PyNumber_Check(arg)"; extra_param_check += " && PyNumber_Check(arg)";
} else { } else {
@ -3173,7 +3192,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
++num_params; ++num_params;
} else if (TypeManager::is_pointer_to_PyObject(type)) { } else if (TypeManager::is_pointer_to_PyObject(type)) {
if (single_arg) { if (args_type == AT_single_arg) {
// This is a single-arg function, so there's no need // This is a single-arg function, so there's no need
// to convert anything. // to convert anything.
param_name = "arg"; param_name = "arg";
@ -3191,7 +3210,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
check_exceptions = true; check_exceptions = true;
} else if (TypeManager::is_pointer_to_Py_buffer(type)) { } else if (TypeManager::is_pointer_to_Py_buffer(type)) {
if (single_arg) { if (args_type == AT_single_arg) {
param_name = "arg"; param_name = "arg";
} else { } else {
indent(out, indent_level) << "PyObject *" << param_name << ";\n"; indent(out, indent_level) << "PyObject *" << param_name << ";\n";
@ -3218,7 +3237,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
expected_params += classNameFromCppName(obj_type->get_simple_name(), false); expected_params += classNameFromCppName(obj_type->get_simple_name(), false);
if (!remap->_has_this || pn != 0) { if (!remap->_has_this || pn != 0) {
if (single_arg) { if (args_type == AT_single_arg) {
param_name = "arg"; param_name = "arg";
} else { } else {
indent(out, indent_level) << "PyObject *" << param_name << ";\n"; indent(out, indent_level) << "PyObject *" << param_name << ";\n";
@ -3278,7 +3297,7 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
} else { } else {
// Ignore a parameter. // Ignore a parameter.
if (single_arg) { if (args_type == AT_single_arg) {
param_name = "arg"; param_name = "arg";
} else { } else {
indent(out, indent_level) << "PyObject *" << param_name << ";\n"; indent(out, indent_level) << "PyObject *" << param_name << ";\n";
@ -3318,7 +3337,9 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
std::string format_specifiers1 = format_specifiers + ":" + std::string format_specifiers1 = format_specifiers + ":" +
methodNameFromCppName(func, "", false); methodNameFromCppName(func, "", false);
if (have_kwargs) { switch (args_type) {
case AT_keyword_args:
// Wrapper takes a varargs tuple and a keyword args dict.
indent(out, indent_level) indent(out, indent_level)
<< "static char *keyword_list[] = {" << keyword_list << "NULL};\n"; << "static char *keyword_list[] = {" << keyword_list << "NULL};\n";
indent(out, indent_level) indent(out, indent_level)
@ -3328,8 +3349,10 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
++open_scopes; ++open_scopes;
indent_level += 2; indent_level += 2;
break;
} else if (have_varargs) { case AT_varargs:
// Wrapper takes a varargs tuple.
if (only_pyobjects) { if (only_pyobjects) {
// All parameters are PyObject*, so we can use the slightly // All parameters are PyObject*, so we can use the slightly
// more efficient PyArg_UnpackTuple function instead. // more efficient PyArg_UnpackTuple function instead.
@ -3347,16 +3370,18 @@ write_function_instance(ostream &out, InterfaceMaker::Object *obj,
} }
++open_scopes; ++open_scopes;
indent_level += 2; indent_level += 2;
break;
} else if (single_arg && !only_pyobjects && case AT_single_arg:
format_specifiers != "" && // Wrapper takes a single PyObject* argument.
format_specifiers != "O") { if (!only_pyobjects && format_specifiers != "O") {
indent(out, indent_level) indent(out, indent_level)
<< "if (PyArg_Parse(arg, \"" << format_specifiers << "\"" << "if (PyArg_Parse(arg, \"" << format_specifiers << "\""
<< parameter_list << ")) {\n"; << parameter_list << ")) {\n";
++open_scopes; ++open_scopes;
indent_level += 2; indent_level += 2;
}
} }
} }
@ -4155,23 +4180,6 @@ is_function_legal(Function *func) {
return false; return false;
} }
////////////////////////////////////////////////////////////////////////
// Function : isFunctionWithThis
//
// If any rempas have a this .. this function has a this..( of self) to python..
////////////////////////////////////////////////////////////////////////
bool InterfaceMakerPythonNative::
isFunctionWithThis(Function *func) {
Function::Remaps::const_iterator ri;
for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
FunctionRemap *remap = (*ri);
if (remap->_has_this) {
return true;
}
}
return false;
}
//////////////////////////////////////////////////////// ////////////////////////////////////////////////////////
// Function : IsRunTimeTyped // Function : IsRunTimeTyped
/////////////////////////////////////////////////////// ///////////////////////////////////////////////////////

View File

@ -27,8 +27,7 @@ class FunctionRemap;
// Description : An InterfaceMaker for generating complex Python // Description : An InterfaceMaker for generating complex Python
// function wrappers around C++ code. // function wrappers around C++ code.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class InterfaceMakerPythonNative : public InterfaceMakerPython class InterfaceMakerPythonNative : public InterfaceMakerPython {
{
public: public:
InterfaceMakerPythonNative(InterrogateModuleDef *def); InterfaceMakerPythonNative(InterrogateModuleDef *def);
virtual ~InterfaceMakerPythonNative(); virtual ~InterfaceMakerPythonNative();
@ -92,27 +91,24 @@ private:
void write_prototype_for_name(ostream &out, Function *func, const std::string &name); void write_prototype_for_name(ostream &out, Function *func, const std::string &name);
void write_prototype_for(ostream &out, Function *func); void write_prototype_for(ostream &out, Function *func);
void write_function_for_top(ostream &out, Object *obj, Function *func, const std::string &PreProcess); void write_function_for_top(ostream &out, Object *obj, Function *func);
void write_function_for_name(ostream &out, Object *obj, Function *func, void write_function_for_name(ostream &out, Object *obj, Function *func,
const std::string &name, const std::string &PreProcess, const std::string &name,
bool coercion_allowed, bool &coercion_attempted, bool coercion_allowed, bool &coercion_attempted,
bool single_arg, bool have_varargs, ArgsType args_type, bool return_int);
bool have_kwargs, bool return_int);
void write_function_forset(ostream &out, Object *obj, Function *func, void write_function_forset(ostream &out, Object *obj, Function *func,
std::set<FunctionRemap*> &remaps, string &expected_params, std::set<FunctionRemap*> &remaps, string &expected_params,
int indent_level, bool inplace, int indent_level, bool inplace,
bool coercion_allowed, bool &coercion_attempted, bool coercion_allowed, bool &coercion_attempted,
bool single_arg, bool have_varargs, ArgsType args_type, bool return_int,
bool have_kwargs, bool return_int,
const string &first_expr = string()); const string &first_expr = string());
void write_function_instance(ostream &out, Object *obj, Function *func, void write_function_instance(ostream &out, Object *obj, Function *func,
FunctionRemap *remap, string &expected_params, FunctionRemap *remap, string &expected_params,
int indent_level, bool is_inplace, int indent_level, bool is_inplace,
bool coercion_allowed, bool &coercion_attempted, bool coercion_allowed, bool &coercion_attempted,
bool single_arg, bool have_varargs, ArgsType args_type, bool return_int,
bool have_kwargs, bool return_int,
const string &first_pexpr = string()); const string &first_pexpr = string());
void pack_return_value(ostream &out, int indent_level, FunctionRemap *remap, void pack_return_value(ostream &out, int indent_level, FunctionRemap *remap,

View File

@ -1863,26 +1863,34 @@ get_type(CPPType *type, bool global) {
// First, check to see if it's already there. // First, check to see if it's already there.
string true_name = type->get_local_name(&parser); string true_name = type->get_local_name(&parser);
TypesByName::const_iterator tni = _types_by_name.find(true_name);
if (tni != _types_by_name.end()) {
// It's already here, so update the global flag.
index = (*tni).second;
if (index == 0) {
// This is an invalid type; we don't know anything about it.
return 0;
}
InterrogateType &itype = InterrogateDatabase::get_ptr()->update_type(index); if (true_name.empty()) {
if (global) { // Whoops, it's an anonymous type. That's okay, because we'll
itype._flags |= InterrogateType::F_global; // usually only encounter them once anyway, so let's go ahead and
} // define it without checking in _types_by_name.
if ((itype._flags & InterrogateType::F_fully_defined) != 0) { } else {
return index; TypesByName::const_iterator tni = _types_by_name.find(true_name);
} if (tni != _types_by_name.end()) {
// It's already here, so update the global flag.
index = (*tni).second;
if (index == 0) {
// This is an invalid type; we don't know anything about it.
return 0;
}
// But wait--it's not fully defined yet! We'll go ahead and InterrogateType &itype = InterrogateDatabase::get_ptr()->update_type(index);
// define it now. if (global) {
itype._flags |= InterrogateType::F_global;
}
if ((itype._flags & InterrogateType::F_fully_defined) != 0) {
return index;
}
// But wait--it's not fully defined yet! We'll go ahead and
// define it now.
}
} }
bool forced = in_forcetype(true_name); bool forced = in_forcetype(true_name);
@ -1890,7 +1898,9 @@ get_type(CPPType *type, bool global) {
if (index == 0) { if (index == 0) {
// It isn't already there, so we have to define it. // It isn't already there, so we have to define it.
index = InterrogateDatabase::get_ptr()->get_next_index(); index = InterrogateDatabase::get_ptr()->get_next_index();
_types_by_name[true_name] = index; if (!true_name.empty()) {
_types_by_name[true_name] = index;
}
InterrogateType itype; InterrogateType itype;
if (global) { if (global) {
@ -1904,7 +1914,7 @@ get_type(CPPType *type, bool global) {
InterrogateDatabase::get_ptr()->update_type(index); InterrogateDatabase::get_ptr()->update_type(index);
itype._name = get_preferred_name(type); itype._name = get_preferred_name(type);
int num_alt_names = type->get_num_alt_names(); int num_alt_names = type->get_num_alt_names();
if (num_alt_names != 0) { if (num_alt_names != 0) {
itype._alt_names.clear(); itype._alt_names.clear();
@ -1954,23 +1964,19 @@ get_type(CPPType *type, bool global) {
} }
} }
if (forced || !in_ignoretype(true_name)) if (forced || !in_ignoretype(true_name)) {
{
itype._flags |= InterrogateType::F_fully_defined; itype._flags |= InterrogateType::F_fully_defined;
if (type->as_simple_type() != (CPPSimpleType *)NULL) if (type->as_simple_type() != (CPPSimpleType *)NULL) {
{
define_atomic_type(itype, type->as_simple_type()); define_atomic_type(itype, type->as_simple_type());
} else if (type->as_pointer_type() != (CPPPointerType *)NULL) } else if (type->as_pointer_type() != (CPPPointerType *)NULL) {
{
define_wrapped_type(itype, type->as_pointer_type()); define_wrapped_type(itype, type->as_pointer_type());
} else if (type->as_const_type() != (CPPConstType *)NULL) { } else if (type->as_const_type() != (CPPConstType *)NULL) {
define_wrapped_type(itype, type->as_const_type()); define_wrapped_type(itype, type->as_const_type());
} else if (type->as_struct_type() != (CPPStructType *)NULL) } else if (type->as_struct_type() != (CPPStructType *)NULL) {
{
define_struct_type(itype, type->as_struct_type(), index, forced); define_struct_type(itype, type->as_struct_type(), index, forced);
} else if (type->as_enum_type() != (CPPEnumType *)NULL) { } else if (type->as_enum_type() != (CPPEnumType *)NULL) {
@ -1984,7 +1990,9 @@ get_type(CPPType *type, bool global) {
// Remove the type from the database. // Remove the type from the database.
InterrogateDatabase::get_ptr()->remove_type(index); InterrogateDatabase::get_ptr()->remove_type(index);
_types_by_name[true_name] = 0; if (!true_name.empty()) {
_types_by_name[true_name] = 0;
}
index = 0; index = 0;
} }
} }
@ -2229,6 +2237,7 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
for (di = scope->_declarations.begin(); for (di = scope->_declarations.begin();
di != scope->_declarations.end(); di != scope->_declarations.end();
++di) { ++di) {
if ((*di)->get_subtype() == CPPDeclaration::ST_instance) { if ((*di)->get_subtype() == CPPDeclaration::ST_instance) {
CPPInstance *inst = (*di)->as_instance(); CPPInstance *inst = (*di)->as_instance();
if (inst->_type->get_subtype() == CPPDeclaration::ST_function) { if (inst->_type->get_subtype() == CPPDeclaration::ST_function) {
@ -2243,15 +2252,12 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
} }
} }
} else if ((*di)->get_subtype() == CPPDeclaration::ST_type_declaration) } else if ((*di)->get_subtype() == CPPDeclaration::ST_type_declaration) {
{
CPPType *type = (*di)->as_type_declaration()->_type; CPPType *type = (*di)->as_type_declaration()->_type;
if ((*di)->_vis <= min_vis || in_forcetype(type->get_local_name(&parser))) if ((*di)->_vis <= min_vis || in_forcetype(type->get_local_name(&parser))) {
{
if (type->as_struct_type() != (CPPStructType *)NULL || if (type->as_struct_type() != (CPPStructType *)NULL ||
type->as_enum_type() != (CPPEnumType *)NULL) type->as_enum_type() != (CPPEnumType *)NULL) {
{
// Here's a nested class or enum definition. // Here's a nested class or enum definition.
type->_vis = (*di)->_vis; type->_vis = (*di)->_vis;
@ -2259,13 +2265,20 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
assert(nested_type != (CPPExtensionType *)NULL); assert(nested_type != (CPPExtensionType *)NULL);
// Only try to export named types. // Only try to export named types.
if (nested_type->_ident != (CPPIdentifier *)NULL) if (nested_type->_ident != (CPPIdentifier *)NULL) {
{
TypeIndex nested_index = get_type(nested_type, false); TypeIndex nested_index = get_type(nested_type, false);
itype._nested_types.push_back(nested_index); itype._nested_types.push_back(nested_index);
} }
} }
} }
} else if ((*di)->get_subtype() == CPPDeclaration::ST_enum) {
CPPType *type = (*di)->as_enum_type();
// An anonymous enum type.
if ((*di)->_vis <= min_vis) {
TypeIndex nested_index = get_type(type, false);
itype._nested_types.push_back(nested_index);
}
} }
} }