Browse Source

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

rdb 11 years ago
parent
commit
f02662d4e0

+ 10 - 8
dtool/src/interrogate/functionRemap.cxx

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

+ 1 - 4
dtool/src/interrogate/functionRemap.h

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

+ 6 - 11
dtool/src/interrogate/interfaceMaker.cxx

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

+ 23 - 0
dtool/src/interrogate/interfaceMaker.h

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

+ 169 - 161
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -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;
-      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());
+      write_function_for_top(out, obj, func);
     }
     }
   }
   }
 
 
@@ -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;
-      if (func->_flags & FunctionRemap::F_keyword_args) {
+      string flags;
+      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;
-    if (func->_flags & FunctionRemap::F_keyword_args) {
+    string flags;
+    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()) {
+    assert(func->_args_type == AT_no_args);
   }
   }
 
 
-  if (func->_ifunc.is_unary_op()) {
-    assert(!single_arg);
-    assert(!have_varargs);
-    assert(!have_kwargs);
+  fname = "static PyObject *" + func->_name + "(PyObject *";
+
+  // This will be NULL for static funcs, so prevent code from using it.
+  if (func->_has_this) {
+    fname += "self";
   }
   }
 
 
-  if (have_kwargs) {
-    fname = "static PyObject *" + func->_name + "(PyObject *self, PyObject *args, PyObject *kwds)";
-  } else if (have_varargs) {
-    fname = "static PyObject *" + func->_name + "(PyObject *self, PyObject *args)";
-  } else if (single_arg) {
-    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, 
-                        const std::string &function_name, const std::string &PreProcess,
-                        bool coercion_allowed, bool &coercion_attempted, bool single_arg,
-                        bool have_varargs, bool have_kwargs, bool return_int) {
+write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMaker::Function *func,
+                        const std::string &function_name,
+                        bool coercion_allowed, bool &coercion_attempted,
+                        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 have_varargs, bool have_kwargs,
-                      bool return_int,
-                      const string &first_pexpr) {
+                      bool &coercion_attempted,
+                      ArgsType args_type,
+                      bool return_int, 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,
-                        bool have_kwargs, bool return_int,
+                        ArgsType args_type, 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 &&
-               format_specifiers != "" &&
-               format_specifiers != "O") {
-      indent(out, indent_level)
-        << "if (PyArg_Parse(arg, \"" << format_specifiers << "\""
-        << parameter_list << ")) {\n";
+    case AT_single_arg:
+      // Wrapper takes a single PyObject* argument.
+      if (!only_pyobjects && format_specifiers != "O") {
+        indent(out, indent_level)
+          << "if (PyArg_Parse(arg, \"" << format_specifiers << "\""
+          << parameter_list << ")) {\n";
 
 
-      ++open_scopes;
-      indent_level += 2;
+        ++open_scopes;
+        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
 ///////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////

+ 6 - 10
dtool/src/interrogate/interfaceMakerPythonNative.h

@@ -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,
-                               bool have_kwargs, bool return_int);
+                               ArgsType args_type, 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,
-                             bool have_kwargs, bool return_int,
+                             ArgsType args_type, 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,
-                               bool have_kwargs, bool return_int,
+                               ArgsType args_type, 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,

+ 49 - 36
dtool/src/interrogate/interrogateBuilder.cxx

@@ -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 (global) {
-      itype._flags |= InterrogateType::F_global;
-    }
+  if (true_name.empty()) {
+    // Whoops, it's an anonymous type.  That's okay, because we'll
+    // 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) {
-      return index;
-    }
+  } else {
+    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 (global) {
+        itype._flags |= InterrogateType::F_global;
+      }
 
 
-    // But wait--it's not fully defined yet!  We'll go ahead and
-    // define it now.
+      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);
+      }
     }
     }
   }
   }