Browse Source

first wave of new ffi/interrogate

David Rose 24 years ago
parent
commit
861c762e7d
56 changed files with 5905 additions and 842 deletions
  1. 3 0
      dtool/src/cppparser/cppArrayType.cxx
  2. 112 31
      dtool/src/cppparser/cppExpression.cxx
  3. 4 0
      dtool/src/cppparser/cppParameterList.cxx
  4. 18 6
      dtool/src/cppparser/cppPointerType.cxx
  5. 3 0
      dtool/src/cppparser/cppReferenceType.cxx
  6. 25 5
      dtool/src/interrogate/Sources.pp
  7. 55 0
      dtool/src/interrogate/classBuilder.cxx
  8. 58 0
      dtool/src/interrogate/classBuilder.h
  9. 104 0
      dtool/src/interrogate/classBuilderPythonObj.cxx
  10. 45 0
      dtool/src/interrogate/classBuilderPythonObj.h
  11. 585 0
      dtool/src/interrogate/functionRemap.cxx
  12. 123 0
      dtool/src/interrogate/functionRemap.h
  13. 93 0
      dtool/src/interrogate/functionWriter.cxx
  14. 47 0
      dtool/src/interrogate/functionWriter.h
  15. 117 0
      dtool/src/interrogate/functionWriterPtrFromPython.cxx
  16. 48 0
      dtool/src/interrogate/functionWriterPtrFromPython.h
  17. 96 0
      dtool/src/interrogate/functionWriterPtrToPython.cxx
  18. 46 0
      dtool/src/interrogate/functionWriterPtrToPython.h
  19. 91 0
      dtool/src/interrogate/functionWriters.cxx
  20. 56 0
      dtool/src/interrogate/functionWriters.h
  21. 751 0
      dtool/src/interrogate/interfaceMaker.cxx
  22. 148 0
      dtool/src/interrogate/interfaceMaker.h
  23. 242 0
      dtool/src/interrogate/interfaceMakerC.cxx
  24. 62 0
      dtool/src/interrogate/interfaceMakerC.h
  25. 73 0
      dtool/src/interrogate/interfaceMakerPython.cxx
  26. 46 0
      dtool/src/interrogate/interfaceMakerPython.h
  27. 574 0
      dtool/src/interrogate/interfaceMakerPythonObj.cxx
  28. 77 0
      dtool/src/interrogate/interfaceMakerPythonObj.h
  29. 419 0
      dtool/src/interrogate/interfaceMakerPythonSimple.cxx
  30. 71 0
      dtool/src/interrogate/interfaceMakerPythonSimple.h
  31. 18 4
      dtool/src/interrogate/interrogate.cxx
  32. 2 1
      dtool/src/interrogate/interrogate.h
  33. 461 349
      dtool/src/interrogate/interrogateBuilder.cxx
  34. 27 13
      dtool/src/interrogate/interrogateBuilder.h
  35. 5 5
      dtool/src/interrogate/parameterRemapThis.cxx
  36. 2 2
      dtool/src/interrogate/parameterRemapThis.h
  37. 14 0
      dtool/src/interrogate/typeManager.cxx
  38. 2 0
      dtool/src/interrogate/typeManager.h
  39. 270 212
      dtool/src/interrogate/wrapperBuilder.cxx
  40. 69 35
      dtool/src/interrogate/wrapperBuilder.h
  41. 81 36
      dtool/src/interrogate/wrapperBuilderC.cxx
  42. 3 0
      dtool/src/interrogate/wrapperBuilderC.h
  43. 148 116
      dtool/src/interrogate/wrapperBuilderPython.cxx
  44. 7 2
      dtool/src/interrogate/wrapperBuilderPython.h
  45. 457 0
      dtool/src/interrogate/wrapperBuilderPythonObj.cxx
  46. 56 0
      dtool/src/interrogate/wrapperBuilderPythonObj.h
  47. 1 0
      dtool/src/interrogatedb/interrogateComponent.h
  48. 0 17
      dtool/src/interrogatedb/interrogateFunction.I
  49. 20 0
      dtool/src/interrogatedb/interrogateFunction.cxx
  50. 23 3
      dtool/src/interrogatedb/interrogateFunction.h
  51. 2 1
      dtool/src/interrogatedb/interrogateFunctionWrapper.h
  52. 3 0
      dtool/src/interrogatedb/interrogateType.I
  53. 3 0
      dtool/src/interrogatedb/interrogateType.cxx
  54. 11 0
      dtool/src/interrogatedb/interrogateType.h
  55. 4 4
      dtool/src/interrogatedb/interrogate_interface.h
  56. 24 0
      dtool/src/pystub/pystub.cxx

+ 3 - 0
dtool/src/cppparser/cppArrayType.cxx

@@ -140,12 +140,15 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
 ////////////////////////////////////////////////////////////////////
 void CPPArrayType::
 output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
+  /*
   _element_type->output(out, indent_level, scope, complete);
   out << "[";
   if (_bounds != NULL) {
     out << *_bounds;
   }
   out << "]";
+  */
+  output_instance(out, indent_level, scope, complete, "", "");
 }
 
 ////////////////////////////////////////////////////////////////////

+ 112 - 31
dtool/src/cppparser/cppExpression.cxx

@@ -963,7 +963,7 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     break;
 
   case T_variable:
-    out << *_u._variable->_ident;
+    _u._variable->_ident->output(out, scope);
     break;
 
   case T_function:
@@ -971,18 +971,22 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     break;
 
   case T_unknown_ident:
-    out << *_u._ident;
+    _u._ident->output(out, scope);
     break;
 
   case T_typecast:
     out << "(";
     _u._typecast._to->output(out, indent_level, scope, false);
-    out << ")(" << *_u._typecast._op1 << ")";
+    out << ")(";
+    _u._typecast._op1->output(out, indent_level, scope, false);
+    out << ")";
     break;
 
   case T_construct:
     out << "(" << _u._typecast._to->get_typedef_name(scope)
-        << "(" << *_u._typecast._op1 << "))";
+        << "(";
+    _u._typecast._op1->output(out, indent_level, scope, false);
+    out << "))";
     break;
 
   case T_default_construct:
@@ -990,12 +994,17 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     break;
 
   case T_new:
-    out << "(new " << *_u._typecast._to
-        << "(" << *_u._typecast._op1 << "))";
+    out << "(new ";
+    _u._typecast._to->output(out, indent_level, scope, false);
+    out << "(";
+    _u._typecast._op1->output(out, indent_level, scope, false);
+    out << "))";
     break;
 
   case T_default_new:
-    out << "(new " << *_u._typecast._to << "())";
+    out << "(new ";
+    _u._typecast._to->output(out, indent_level, scope, false);
+    out << "())";
     break;
 
   case T_sizeof:
@@ -1007,31 +1016,45 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
   case T_unary_operation:
     switch (_u._op._operator) {
     case UNARY_NOT:
-      out << "(! " << *_u._op._op1 << ")";
+      out << "(! ";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case UNARY_NEGATE:
-      out << "(~ " << *_u._op._op1 << ")";
+      out << "(~ ";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case UNARY_MINUS:
-      out << "(- " << *_u._op._op1 << ")";
+      out << "(- ";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case UNARY_STAR:
-      out << "(* " << *_u._op._op1 << ")";
+      out << "(* ";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case UNARY_REF:
-      out << "(& " << *_u._op._op1 << ")";
+      out << "(& ";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case 'f': // Function evaluation, no parameters.
-      out << "(" << *_u._op._op1 << "())";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << "())";
       break;
 
     default:
-      out << "(" << (char)_u._op._operator << " " << *_u._op._op1 << ")";
+      out << "(" << (char)_u._op._operator << " ";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << ")";
       break;
     }
     break;
@@ -1039,66 +1062,124 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
   case T_binary_operation:
     switch (_u._op._operator) {
     case OROR:
-      out << "(" << *_u._op._op1 << " || " << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << " || ";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case ANDAND:
-      out << "(" << *_u._op._op1 << " && " << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << " && ";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case EQCOMPARE:
-      out << "(" << *_u._op._op1 << " == " << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << " == ";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case NECOMPARE:
-      out << "(" << *_u._op._op1 << " != " << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << " != ";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case LECOMPARE:
-      out << "(" << *_u._op._op1 << " <= " << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << " <= ";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case GECOMPARE:
-      out << "(" << *_u._op._op1 << " >= " << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << " >= ";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case LSHIFT:
-      out << "(" << *_u._op._op1 << " << " << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << " << ";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case RSHIFT:
-      out << "(" << *_u._op._op1 << " >> " << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << " >> ";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case '.':
-      out << "(" << *_u._op._op1 << "." << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << ".";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case POINTSAT:
-      out << "(" << *_u._op._op1 << "->" << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << "->";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
       break;
 
     case '[': // Array element reference
-      out << "(" << *_u._op._op1 << "[" << *_u._op._op2 << "])";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << "[";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << "])";
       break;
 
     case 'f': // Function evaluation
-      out << "(" << *_u._op._op1 << "(" << *_u._op._op2 << "))";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << "(";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << "))";
       break;
 
     case ',': // Comma, no parens are used
-      out << *_u._op._op1 << ", " << *_u._op._op2;
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << ", ";
+      _u._op._op2->output(out, indent_level, scope, false);
       break;
 
     default:
-      out << "(" << *_u._op._op1 << " " << (char)_u._op._operator
-          << " " << *_u._op._op2 << ")";
+      out << "(";
+      _u._op._op1->output(out, indent_level, scope, false);
+      out << " " << (char)_u._op._operator << " ";
+      _u._op._op2->output(out, indent_level, scope, false);
+      out << ")";
     }
     break;
 
   case T_trinary_operation:
-    out << "(" << *_u._op._op1 << " ? " << *_u._op._op2
-        << " : " << *_u._op._op3 << ")";
+    out << "(";
+    _u._op._op1->output(out, indent_level, scope, false);
+    out << " ? ";
+    _u._op._op2->output(out, indent_level, scope, false);
+    out << " : ";
+    _u._op._op3->output(out, indent_level, scope, false);
+    out << ")";
     break;
 
   default:

+ 4 - 0
dtool/src/cppparser/cppParameterList.cxx

@@ -244,5 +244,9 @@ output(ostream &out, CPPScope *scope, bool parameter_names,
 
   } else if (_includes_ellipsis) {
     out << "...";
+
+  } else {
+    // No parameters.
+    out << "void";
   }
 }

+ 18 - 6
dtool/src/cppparser/cppPointerType.cxx

@@ -133,16 +133,28 @@ is_equivalent(const CPPType &other) const {
 ////////////////////////////////////////////////////////////////////
 void CPPPointerType::
 output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
-  _pointing_at->output(out, indent_level, scope, complete);
+  /*
   CPPFunctionType *ftype = _pointing_at->as_function_type();
-  if (ftype != NULL &&
-      ((ftype->_flags & CPPFunctionType::F_method_pointer) != 0)) {
-    // We have to output pointers-to-method with a scoping before the
-    // '*'.
-    out << " " << *ftype->_class_owner << "::*";
+  if (ftype != (CPPFunctionType *)NULL) {
+    // Pointers to functions are a bit of a special case; we have to
+    // be a little more careful about where the '*' goes.
+
+    string star = "*";
+    if ((ftype->_flags & CPPFunctionType::F_method_pointer) != 0) {
+      // We have to output pointers-to-method with a scoping before the
+      // '*'.
+      star = ftype->_class_owner->get_fully_scoped_name() + "::*";
+    }
+
+    _pointing_at->output_instance(out, indent_level, scope, complete,
+                                  star, "");
+
   } else {
+    _pointing_at->output(out, indent_level, scope, complete);
     out << " *";
   }
+  */
+  output_instance(out, indent_level, scope, complete, "", "");
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 0
dtool/src/cppparser/cppReferenceType.cxx

@@ -131,8 +131,11 @@ is_equivalent(const CPPType &other) const {
 ////////////////////////////////////////////////////////////////////
 void CPPReferenceType::
 output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
+  /*
   _pointing_at->output(out, indent_level, scope, complete);
   out << " &";
+  */
+  output_instance(out, indent_level, scope, complete, "", "");
 }
 
 ////////////////////////////////////////////////////////////////////

+ 25 - 5
dtool/src/interrogate/Sources.pp

@@ -4,10 +4,20 @@
 
 #begin bin_target
   #define TARGET interrogate
-  
-  #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx   
 
+// While I'm working on this, I'll temporarily take out the composite
+// build.
+//  #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx   
   #define SOURCES \
+     classBuilder.h classBuilderPythonObj.h \
+     functionRemap.h \
+     functionWriter.h \
+     functionWriterPtrFromPython.h functionWriterPtrToPython.h \
+     functionWriters.h \
+     interfaceMaker.h \
+     interfaceMakerC.h \
+     interfaceMakerPython.h interfaceMakerPythonObj.h \
+     interfaceMakerPythonSimple.h \
      interrogate.h interrogateBuilder.h parameterRemap.I  \
      parameterRemap.h parameterRemapBasicStringRefToString.h  \
      parameterRemapBasicStringToString.h  \
@@ -19,9 +29,19 @@
      parameterRemapReferenceToPointer.h parameterRemapThis.h  \
      parameterRemapToString.h parameterRemapUnchanged.h  \
      typeManager.h wrapperBuilder.h wrapperBuilderC.h  \
-     wrapperBuilderPython.h      
+     wrapperBuilderPython.h wrapperBuilderPythonObj.h
 
- #define INCLUDED_SOURCES  \
+// #define INCLUDED_SOURCES  \
+ #define SOURCES $[SOURCES] \
+     classBuilder.cxx classBuilderPythonObj.cxx \
+     functionRemap.cxx \
+     functionWriter.cxx \
+     functionWriterPtrFromPython.cxx functionWriterPtrToPython.cxx \
+     functionWriters.cxx \
+     interfaceMaker.cxx \
+     interfaceMakerC.cxx \
+     interfaceMakerPython.cxx interfaceMakerPythonObj.cxx \
+     interfaceMakerPythonSimple.cxx \
      interrogate.cxx interrogateBuilder.cxx parameterRemap.cxx  \
      parameterRemapBasicStringRefToString.cxx  \
      parameterRemapBasicStringToString.cxx  \
@@ -33,7 +53,7 @@
      parameterRemapReferenceToPointer.cxx parameterRemapThis.cxx  \
      parameterRemapToString.cxx parameterRemapUnchanged.cxx  \
      typeManager.cxx wrapperBuilder.cxx wrapperBuilderC.cxx  \
-     wrapperBuilderPython.cxx  
+     wrapperBuilderPython.cxx wrapperBuilderPythonObj.cxx
 
 #end bin_target
 

+ 55 - 0
dtool/src/interrogate/classBuilder.cxx

@@ -0,0 +1,55 @@
+// Filename: classBuilder.cxx
+// Created by:  drose (17Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "classBuilder.h"
+#include "interrogate.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClassBuilder::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+ClassBuilder::
+ClassBuilder() {
+  _struct_type = (CPPStructType *)NULL;
+  _type_index = -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClassBuilder::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+ClassBuilder::
+~ClassBuilder() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClassBuilder::set_class
+//       Access: Public, Virtual
+//  Description: Sets the class that will be generated by this
+//               ClassBuilder.  Returns true on success, false if the
+//               class cannot be output for some reason.
+////////////////////////////////////////////////////////////////////
+bool ClassBuilder::
+set_class(TypeIndex type_index, CPPStructType *struct_type) {
+  _type_index = type_index;
+  _struct_type = struct_type;
+  return true;
+}

+ 58 - 0
dtool/src/interrogate/classBuilder.h

@@ -0,0 +1,58 @@
+// Filename: classBuilder.h
+// Created by:  drose (17Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CLASSBUILDER_H
+#define CLASSBUILDER_H
+
+#include "dtoolbase.h"
+#include "interrogate_interface.h"
+
+class CPPScope;
+class CPPStructType;
+class InterrogateType;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ClassBuilder
+// Description : Similar to WrapperBuilder, this contains all the
+//               information needed to generate whatever source code
+//               might be associated with a complete class definition
+//               (as opposed to the source code associated with each
+//               function).
+//
+//               This is an abstract class, and is implemented
+//               separately for each kind of generated output.  Most
+//               kinds do not need to write anything special for the
+//               class definition, so do not implement this class.  At
+//               the present, only ClassBuilderPythonObj is necessary.
+////////////////////////////////////////////////////////////////////
+class ClassBuilder {
+public:
+  ClassBuilder();
+  virtual ~ClassBuilder();
+
+  virtual bool set_class(TypeIndex type_index, CPPStructType *struct_type);
+
+  virtual void write_prototype(ostream &out) const=0;
+  virtual void write_code(ostream &out) const=0;
+
+protected:
+  CPPStructType *_struct_type;
+  TypeIndex _type_index;
+};
+
+#endif

+ 104 - 0
dtool/src/interrogate/classBuilderPythonObj.cxx

@@ -0,0 +1,104 @@
+// Filename: classBuilderPythonObj.cxx
+// Created by:  drose (17Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "classBuilderPythonObj.h"
+#include "cppStructType.h"
+#include "interrogateBuilder.h"
+#include "interrogate.h"
+
+#include "interrogateType.h"
+#include "interrogateDatabase.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClassBuilderPythonObj::set_class
+//       Access: Public, Virtual
+//  Description: Sets the class that will be generated by this
+//               ClassBuilder.  Returns true on success, false if the
+//               class cannot be output for some reason.
+////////////////////////////////////////////////////////////////////
+bool ClassBuilderPythonObj::
+set_class(TypeIndex type_index, CPPStructType *struct_type) {
+  if (!ClassBuilder::set_class(type_index, struct_type)) {
+    return false;
+  }
+
+  _name = get_builder_name(_struct_type);
+
+  InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
+  const InterrogateType &itype = idb->get_type(_type_index);
+  int num_methods = itype.number_of_methods();
+  cerr << "    // index = " << _type_index << " methods = " << num_methods
+      << " type = " << itype.get_name() << "\n";
+  for (int i = 0; i < num_methods; i++) {
+    FunctionIndex fi = itype.get_method(i);
+    const InterrogateFunction &func = idb->get_function(fi);
+
+    cerr << "    // " << func.get_name() << "\n";
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClassBuilderPythonObj::write_prototype
+//       Access: Public, Virtual
+//  Description: Generates prototypes for whatever functions will be
+//               generated by write_code().
+////////////////////////////////////////////////////////////////////
+void ClassBuilderPythonObj::
+write_prototype(ostream &out) const {
+  out << "PyObject *" << _name << "();\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClassBuilderPythonObj::write_code
+//       Access: Public, Virtual
+//  Description: Generates whatever code is appropriate for this
+//               class.
+////////////////////////////////////////////////////////////////////
+void ClassBuilderPythonObj::
+write_code(ostream &out) const {
+  out << "PyObject *\n"
+      << _name << "() {\n"
+      << "  static PyObject *wrapper = (PyObject *)NULL;\n"
+      << "  static PyMethodDef methods[] = {\n";
+
+  out << "  };\n"
+      << "  if (wrapper == (PyObject *)NULL) {\n"
+      << "    PyObject *bases = PyTuple_New(0);\n"
+      << "    PyObject *dict = PyDict_New();\n"
+      << "    PyObject *name = PyString_FromString(\"" 
+      << InterrogateBuilder::clean_identifier(_struct_type->get_simple_name())
+      << "\");\n"
+      << "    wrapper = PyClass_New(bases, dict, name);\n"
+      << "  }\n"
+      << "  return wrapper;\n"
+      << "}\n\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ClassBuilderPythonObj::get_builder_name
+//       Access: Public, Static
+//  Description: Returns the name of the ClassBuilder function
+//               generated for the indicated struct type.
+////////////////////////////////////////////////////////////////////
+string ClassBuilderPythonObj::
+get_builder_name(CPPType *struct_type) {
+  return "get_python_class_" + 
+    InterrogateBuilder::clean_identifier(struct_type->get_local_name(&parser));
+}

+ 45 - 0
dtool/src/interrogate/classBuilderPythonObj.h

@@ -0,0 +1,45 @@
+// Filename: classBuilderPythonObj.h
+// Created by:  drose (17Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CLASSBUILDERPYTHONOBJ_H
+#define CLASSBUILDERPYTHONOBJ_H
+
+#include "dtoolbase.h"
+#include "classBuilder.h"
+
+class CPPType;
+
+////////////////////////////////////////////////////////////////////
+//       Class : ClassBuilderPythonObj
+// Description : A specialization on ClassBuilder that builds
+//               actual Python class objects.
+////////////////////////////////////////////////////////////////////
+class ClassBuilderPythonObj : public ClassBuilder {
+public:
+  virtual bool set_class(TypeIndex type_index, CPPStructType *struct_type);
+
+  virtual void write_prototype(ostream &out) const;
+  virtual void write_code(ostream &out) const;
+
+  static string get_builder_name(CPPType *struct_type);
+
+private:
+  string _name;
+};
+
+#endif

+ 585 - 0
dtool/src/interrogate/functionRemap.cxx

@@ -0,0 +1,585 @@
+// Filename: functionRemap.cxx
+// Created by:  drose (19Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "functionRemap.h"
+#include "typeManager.h"
+#include "interrogate.h"
+#include "parameterRemap.h"
+#include "parameterRemapThis.h"
+#include "interfaceMaker.h"
+#include "interrogateBuilder.h"
+
+#include "interrogateDatabase.h"
+#include "cppInstance.h"
+#include "cppFunctionType.h"
+#include "cppParameterList.h"
+#include "cppReferenceType.h"
+#include "interrogateType.h"
+#include "notify.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionRemap::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+FunctionRemap::
+FunctionRemap(const InterrogateType &itype, const InterrogateFunction &ifunc,
+              CPPInstance *cppfunc, int num_default_parameters,
+              InterfaceMaker *interface) {
+  _return_type = (ParameterRemap *)NULL;
+  _void_return = true;
+  _has_this = false;
+  _first_true_parameter = 0;
+  _num_default_parameters = num_default_parameters;
+  _type = T_normal;
+  _wrapper_index = 0;
+
+  _return_value_needs_management = false;
+  _return_value_destructor = 0;
+  _manage_reference_count = false;
+
+  _cppfunc = cppfunc;
+  _ftype = _cppfunc->_type->as_function_type();
+  _cpptype = itype._cpptype;
+  _cppscope = itype._cppscope;
+
+  _is_valid = setup_properties(ifunc, interface);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionRemap::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+FunctionRemap::
+~FunctionRemap() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionRemap::get_parameter_name
+//       Access: Public
+//  Description: Returns a string that will be a suitable name for the
+//               nth parameter in the generated code.  This may not
+//               correspond to the name of the parameter in the
+//               original code.
+////////////////////////////////////////////////////////////////////
+string FunctionRemap::
+get_parameter_name(int n) const {
+  ostringstream str;
+  str << "param" << n;
+  return str.str();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionRemap::call_function
+//       Access: Public
+//  Description: Writes a sequence of commands to the given output
+//               stream to call the wrapped function.  The parameter
+//               values are taken from pexprs, if it is nonempty, or
+//               are assumed to be simply the names of the parameters,
+//               if it is empty.
+//
+//               The return value is the expression to return, if we
+//               are returning a value, or the empty string if we
+//               return nothing.
+////////////////////////////////////////////////////////////////////
+string FunctionRemap::
+call_function(ostream &out, int indent_level, bool convert_result,
+              const string &container, const vector_string &pexprs) const {
+  string return_expr;
+
+  if (_type == T_destructor) {
+    // A destructor wrapper is just a wrapper around the delete operator.
+    assert(!container.empty());
+    assert(_cpptype != (CPPType *)NULL);
+
+    if (TypeManager::is_reference_count(_cpptype)) {
+      // Except for a reference-count type object, in which case the
+      // destructor is a wrapper around unref_delete().
+      InterfaceMaker::indent(out, indent_level)
+        << "unref_delete(" << container << ");\n";
+    } else {
+      InterfaceMaker::indent(out, indent_level)
+        << "delete " << container << ";\n";
+    }
+
+  } else if (_type == T_typecast_method) {
+    // A typecast method can be invoked implicitly.
+    string cast_expr =
+      "(" + _return_type->get_orig_type()->get_local_name(&parser) +
+      ")(*" + container + ")";
+
+    if (!convert_result) {
+      return_expr = cast_expr;
+    } else {
+      string new_str =
+        _return_type->prepare_return_expr(out, indent_level, cast_expr);
+      return_expr = _return_type->get_return_expr(new_str);
+    }
+
+  } else if (_type == T_typecast) {
+    // A regular typecast converts from a pointer type to another
+    // pointer type.  (This is different from the typecast method,
+    // above, which converts from the concrete type to some other
+    // type.)
+    assert(!container.empty());
+    string cast_expr =
+      "(" + _return_type->get_orig_type()->get_local_name(&parser) +
+      ")" + container;
+
+    if (!convert_result) {
+      return_expr = cast_expr;
+    } else {
+      string new_str =
+        _return_type->prepare_return_expr(out, indent_level, cast_expr);
+      return_expr = _return_type->get_return_expr(new_str);
+    }
+
+  } else if (_type == T_constructor) {
+    // A special case for constructors.
+    return_expr = "new " + get_call_str(container, pexprs);
+    if (_void_return) {
+      nout << "Error, constructor for " << *_cpptype << " returning void.\n";
+      return_expr = "";
+    }
+
+  } else if (_type == T_assignment_method) {
+    // Another special case for assignment operators.
+    assert(!container.empty());
+    InterfaceMaker::indent(out, indent_level)
+      << get_call_str(container, pexprs) << ";\n";
+
+    string this_expr = container;
+    string ref_expr = "*" + this_expr;
+
+    if (!convert_result) {
+      return_expr = ref_expr;
+    } else {
+      string new_str =
+        _return_type->prepare_return_expr(out, indent_level, ref_expr);
+      return_expr = _return_type->get_return_expr(new_str);
+
+      // Now a simple special-case test.  Often, we will have converted
+      // the reference-returning assignment operator to a pointer.  In
+      // this case, we might inadventent generate code like "return
+      // &(*this)", when "return this" would do.  We check for this here
+      // and undo it as a special case.
+
+      // There's no real good reason to do this, other than that it
+      // feels more satisfying to a casual perusal of the generated
+      // code.  It *is* conceivable that some broken compilers wouldn't
+      // like "&(*this)", though.
+
+      if (return_expr == "&(" + ref_expr + ")" ||
+          return_expr == "&" + ref_expr) {
+        return_expr = this_expr;
+      }
+    }
+
+  } else if (_void_return) {
+    InterfaceMaker::indent(out, indent_level)
+      << get_call_str(container, pexprs) << ";\n";
+
+  } else {
+    string call = get_call_str(container, pexprs);
+
+    if (!convert_result) {
+      return_expr = get_call_str(container, pexprs);
+
+    } else {
+      if (_return_type->return_value_should_be_simple()) {
+        // We have to assign the result to a temporary first; this makes
+        // it a bit easier on poor old VC++.
+        InterfaceMaker::indent(out, indent_level);
+        _return_type->get_orig_type()->output_instance(out, "result",
+                                                           &parser);
+        out << " = " << call << ";\n";
+
+        string new_str =
+          _return_type->prepare_return_expr(out, indent_level, "result");
+        return_expr = _return_type->get_return_expr(new_str);
+
+      } else {
+        // This should be simple enough that we can return it directly.
+        string new_str =
+          _return_type->prepare_return_expr(out, indent_level, call);
+        return_expr = _return_type->get_return_expr(new_str);
+      }
+    }
+  }
+
+  return return_expr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionRemap::write_orig_prototype
+//       Access: Public
+//  Description: Writes a line describing the original C++ method or
+//               function.  This is generally useful only within a
+//               comment.
+////////////////////////////////////////////////////////////////////
+void FunctionRemap::
+write_orig_prototype(ostream &out, int indent_level) const {
+  _cppfunc->output(out, indent_level, &parser, false, _num_default_parameters);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionRemap::make_wrapper_entry
+//       Access: Public
+//  Description: Creates an InterrogateFunctionWrapper object
+//               corresponding to this callable instance and stores it
+//               in the database.
+////////////////////////////////////////////////////////////////////
+FunctionWrapperIndex FunctionRemap::
+make_wrapper_entry(FunctionIndex function_index) {
+  _wrapper_index =
+    InterrogateDatabase::get_ptr()->get_next_index();
+
+  InterrogateFunctionWrapper iwrapper;
+  iwrapper._function = function_index;
+  iwrapper._name = _wrapper_name;
+  iwrapper._unique_name = _unique_name;
+
+  if (true_wrapper_names) {
+    // If we're reporting "true" names, it means we set the
+    // wrapper's name to the name of the function it wraps.
+    iwrapper._name = 
+      InterrogateBuilder::clean_identifier(_cppfunc->get_local_name(&parser));
+  }
+  if (output_function_names) {
+    // If we're keeping the function names, record that the wrapper is
+    // callable.
+    iwrapper._flags |= InterrogateFunctionWrapper::F_callable_by_name;
+  }
+
+  Parameters::const_iterator pi;
+  for (pi = _parameters.begin();
+       pi != _parameters.end();
+       ++pi) {
+    InterrogateFunctionWrapper::Parameter param;
+    param._parameter_flags = 0;
+    if ((*pi)._remap->new_type_is_atomic_string()) {
+      param._type = builder.get_atomic_string_type();
+    } else {
+      param._type = builder.get_type((*pi)._remap->get_new_type(), false);
+    }
+    param._name = (*pi)._name;
+    if ((*pi)._has_name) {
+      param._parameter_flags |= InterrogateFunctionWrapper::PF_has_name;
+    }
+    iwrapper._parameters.push_back(param);
+  }
+
+  if (_has_this) {
+    // If one of the parameters is "this", it must be the first one.
+    assert(!iwrapper._parameters.empty());
+    iwrapper._parameters.front()._parameter_flags |=
+      InterrogateFunctionWrapper::PF_is_this;
+  }
+
+  if (!_void_return) {
+    iwrapper._flags |= InterrogateFunctionWrapper::F_has_return;
+  }
+
+  if (_return_type->new_type_is_atomic_string()) {
+    iwrapper._return_type = builder.get_atomic_string_type();
+  } else {
+    iwrapper._return_type =
+      builder.get_type(_return_type->get_new_type(), false);
+  }
+
+  if (_return_value_needs_management) {
+    iwrapper._flags |= InterrogateFunctionWrapper::F_caller_manages;
+    FunctionIndex destructor = _return_value_destructor;
+    
+    if (destructor != 0) {
+      iwrapper._return_value_destructor = destructor;
+      
+    } else {
+      // We don't need to report this warning, since the FFI code
+      // understands that if the destructor function is zero, it
+      // should use the regular class destructor.
+      
+      //          nout << "Warning!  Destructor for " 
+      //               << *_return_type->get_orig_type()
+      //               << " is unavailable.\n"
+      //               << "  Cannot manage return value for:\n  "
+      //               << description << "\n";
+    }
+  }
+
+  InterrogateDatabase::get_ptr()->add_wrapper(_wrapper_index, iwrapper);
+  return _wrapper_index;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionRemap::get_call_str
+//       Access: Private
+//  Description: Returns a string suitable for calling the wrapped
+//               function.  If pexprs is nonempty, it represents
+//               the list of expressions that will evaluate to each
+//               parameter value.
+////////////////////////////////////////////////////////////////////
+string FunctionRemap::
+get_call_str(const string &container, const vector_string &pexprs) const {
+  // Build up the call to the actual function.
+  ostringstream call;
+
+  // Getters and setters are a special case.
+  if (_type == T_getter) {
+    if (!container.empty()) {
+      call << "(" << container << ")->" << _expression;
+    } else {
+      call << _expression;
+    }
+
+  } else if (_type == T_setter) {
+    if (!container.empty()) {
+      call << "(" << container << ")->" << _expression;
+    } else {
+      call << _expression;
+    }
+
+    call << " = ";
+    _parameters[0]._remap->pass_parameter(call, get_parameter_expr(_first_true_parameter, pexprs));
+
+  } else {
+    if (_type == T_constructor) {
+      // Constructors are called differently.
+      call << _cpptype->get_local_name(&parser);
+
+    } else if (_has_this && !container.empty()) {
+      // If we have a "this" parameter, the calling convention is also
+      // a bit different.
+      call << "(" << container << ")->" << _cppfunc->get_local_name();
+      
+    } else {
+      call << _cppfunc->get_local_name(&parser);
+    }
+
+    call << "(";
+    int pn = _first_true_parameter;
+    if (pn < (int)_parameters.size()) {
+      _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
+      pn++;
+      while (pn < (int)_parameters.size()) {
+        call << ", ";
+        _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
+        pn++;
+      }
+    }
+    call << ")";
+  }
+
+  return call.str();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionRemap::get_parameter_expr
+//       Access: Private
+//  Description: Returns a string that represents the expression
+//               associated with the nth parameter.  This is just the
+//               nth element of pexprs if it is nonempty, or the name
+//               of the nth parameter is it is empty.
+////////////////////////////////////////////////////////////////////
+string FunctionRemap::
+get_parameter_expr(int n, const vector_string &pexprs) const {
+  if (n < (int)pexprs.size()) {
+    return pexprs[n];
+  }
+  return get_parameter_name(n);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionRemap::setup_properties
+//       Access: Private
+//  Description: Sets up the properties of the function appropriately.
+//               Returns true if successful, or false if there is
+//               something unacceptable about the function.
+////////////////////////////////////////////////////////////////////
+bool FunctionRemap::
+setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface) {
+  _function_signature = 
+    TypeManager::get_function_signature(_cppfunc, _num_default_parameters);
+  _expression = ifunc._expression;
+
+  if ((_ftype->_flags & CPPFunctionType::F_constructor) != 0) {
+    _type = T_constructor;
+
+  } else if ((_ftype->_flags & CPPFunctionType::F_destructor) != 0) {
+    _type = T_destructor;
+
+  } else if ((_ftype->_flags & CPPFunctionType::F_operator_typecast) != 0) {
+    _type = T_typecast_method;
+
+  } else if ((ifunc._flags & InterrogateFunction::F_typecast) != 0) {
+    _type = T_typecast;
+
+  } else if ((ifunc._flags & InterrogateFunction::F_getter) != 0) {
+    _type = T_getter;
+
+  } else if ((ifunc._flags & InterrogateFunction::F_setter) != 0) {
+    _type = T_setter;
+  }
+
+  if (_cpptype != (CPPType *)NULL &&
+      ((_cppfunc->_storage_class & CPPInstance::SC_static) == 0) &&
+      _type != T_constructor) {
+
+    // If this is a method, but not a static method, and not a
+    // constructor, then we need a "this" parameter.
+    _has_this = true;
+
+    if (interface->synthesize_this_parameter()) {
+      // If the interface demands it, the "this" parameter is treated
+      // as any other parameter, and inserted at the beginning of the
+      // parameter list.
+      Parameter param;
+      param._name = "this";
+      param._has_name = true;
+      bool is_const = (_ftype->_flags & CPPFunctionType::F_const_method) != 0;
+      param._remap = new ParameterRemapThis(_cpptype, is_const);
+      _parameters.push_back(param);
+      _first_true_parameter = 1;
+    }
+      
+    // Also check the name of the function.  If it's one of the
+    // assignment-style operators, flag it as such.
+    string fname = _cppfunc->get_simple_name();
+    if (fname == "operator =" ||
+        fname == "operator *=" ||
+        fname == "operator /=" ||
+        fname == "operator %=" ||
+        fname == "operator +=" ||
+        fname == "operator -=" ||
+        fname == "operator |=" ||
+        fname == "operator &=" ||
+        fname == "operator ^=" ||
+        fname == "operator <<=" ||
+        fname == "operator >>=") {
+      _type = T_assignment_method;
+    }
+  }
+
+  const CPPParameterList::Parameters &params =
+    _ftype->_parameters->_parameters;
+  for (int i = 0; i < (int)params.size() - _num_default_parameters; i++) {
+    CPPType *type = params[i]->_type->resolve_type(&parser, _cppscope);
+    Parameter param;
+    param._has_name = true;
+    param._name = params[i]->get_simple_name();
+
+    if (param._name.empty()) {
+      // If the parameter has no name, record it as being nameless,
+      // but also synthesize one in case someone asks anyway.
+      param._has_name = false;
+      ostringstream param_name;
+      param_name << "param" << i;
+      param._name = param_name.str();
+    }
+
+    param._remap = interface->remap_parameter(_cpptype, type);
+    if (param._remap == (ParameterRemap *)NULL) {
+      // If we can't handle one of the parameter types, we can't call
+      // the function.
+      return false;
+    }
+    param._remap->set_default_value(params[i]->_initializer);
+
+    if (!param._remap->is_valid()) {
+      return false;
+    }
+
+    _parameters.push_back(param);
+  }
+
+  if (_type == T_constructor) {
+    // Constructors are a special case.  These appear to return void
+    // as seen by the parser, but we know they actually return a new
+    // concrete instance.
+
+    if (_cpptype == (CPPType *)NULL) {
+      nout << "Method " << *_cppfunc << " has no struct type\n";
+      return false;
+    }
+
+    _return_type = interface->remap_parameter(_cpptype, _cpptype);
+    if (_return_type != (ParameterRemap *)NULL) {
+      _void_return = false;
+    }
+
+  } else if (_type == T_assignment_method) {
+    // Assignment-type methods are also a special case.  We munge
+    // these to return *this, which is a semi-standard C++ convention
+    // anyway.  We just enforce it.
+
+    if (_cpptype == (CPPType *)NULL) {
+      nout << "Method " << *_cppfunc << " has no struct type\n";
+      return false;
+    } else {
+      CPPType *ref_type = CPPType::new_type(new CPPReferenceType(_cpptype));
+      _return_type = interface->remap_parameter(_cpptype, ref_type);
+      if (_return_type != (ParameterRemap *)NULL) {
+        _void_return = false;
+      }
+    }
+
+  } else {
+    // The normal case.
+    CPPType *rtype = _ftype->_return_type->resolve_type(&parser, _cppscope);
+    _return_type = interface->remap_parameter(_cpptype, rtype);
+    if (_return_type != (ParameterRemap *)NULL) {
+      _void_return = TypeManager::is_void(rtype);
+    }
+  }
+
+  if (_return_type == (ParameterRemap *)NULL || 
+      !_return_type->is_valid()) {
+    // If our return type isn't something we can deal with, treat the
+    // function as if it returns NULL.
+    _void_return = true;
+    CPPType *void_type = TypeManager::get_void_type();
+    _return_type = interface->remap_parameter(_cpptype, void_type);
+    assert(_return_type != (ParameterRemap *)NULL);
+  }
+  
+  // Do we need to manage the return value?
+  _return_value_needs_management = 
+    _return_type->return_value_needs_management();
+  _return_value_destructor = 
+    _return_type->get_return_value_destructor();
+  
+  // Should we manage a reference count?
+  CPPType *return_type = _return_type->get_new_type();
+  CPPType *return_meat_type = TypeManager::unwrap_pointer(return_type);
+  
+  if (manage_reference_counts &&
+      TypeManager::is_reference_count_pointer(return_type) &&
+      !TypeManager::has_protected_destructor(return_meat_type)) {
+    // Yes!
+    _manage_reference_count = true;
+    _return_value_needs_management = true;
+    
+    // This is problematic, because we might not have the class in
+    // question fully defined here, particularly if the class is
+    // defined in some other library.
+    _return_value_destructor = builder.get_destructor_for(return_meat_type);
+  }
+
+  return true;
+}

+ 123 - 0
dtool/src/interrogate/functionRemap.h

@@ -0,0 +1,123 @@
+// Filename: functionRemap.h
+// Created by:  drose (19Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef FUNCTIONREMAP_H
+#define FUNCTIONREMAP_H
+
+#include "dtoolbase.h"
+
+#include "interrogate_interface.h"
+#include "vector_string.h"
+
+#include <vector>
+
+class InterrogateBuilder;
+class InterrogateType;
+class InterrogateFunction;
+class ParameterRemap;
+class CPPType;
+class CPPInstance;
+class CPPStructType;
+class CPPScope;
+class CPPFunctionType;
+class InterfaceMaker;
+
+////////////////////////////////////////////////////////////////////
+//       Class : FunctionRemap
+// Description : This class describes how to remap a C++ function (and
+//               its list of parameters and return type) to a wrapped
+//               function, for a particular scripting language.
+//
+//               The InterfaceMaker class will create one of these for
+//               each function, including one for each instance of an
+//               overloaded function.
+////////////////////////////////////////////////////////////////////
+class FunctionRemap {
+public:
+  FunctionRemap(const InterrogateType &itype,
+                const InterrogateFunction &ifunc,
+                CPPInstance *cppfunc, int num_default_parameters,
+                InterfaceMaker *interface);
+  ~FunctionRemap();
+
+  string get_parameter_name(int n) const;
+  string call_function(ostream &out, int indent_level, 
+                       bool convert_result, const string &container,
+                       const vector_string &pexprs = vector_string()) const;
+
+  void write_orig_prototype(ostream &out, int indent_level) const;
+
+  FunctionWrapperIndex make_wrapper_entry(FunctionIndex function_index);
+
+  class Parameter {
+  public:
+    bool _has_name;
+    string _name;
+    ParameterRemap *_remap;
+  };
+
+  enum Type {
+    T_normal,
+    T_constructor,
+    T_destructor,
+    T_typecast_method,
+    T_assignment_method,
+    T_typecast,
+    T_getter,
+    T_setter
+  };
+
+  typedef vector<Parameter> Parameters;
+
+  Parameters _parameters;
+  ParameterRemap *_return_type;
+  bool _void_return;
+  bool _has_this;
+  int _first_true_parameter;
+  int _num_default_parameters;
+  Type _type;
+  string _expression;
+  string _function_signature;
+  string _hash;
+  string _unique_name;
+  string _wrapper_name;
+  FunctionWrapperIndex _wrapper_index;
+  
+  bool _return_value_needs_management;
+  FunctionIndex _return_value_destructor;
+  bool _manage_reference_count;
+
+  CPPType *_cpptype;
+  CPPScope *_cppscope;
+  CPPInstance *_cppfunc;
+  CPPFunctionType *_ftype;
+
+  bool _is_valid;
+
+private:
+  string
+  get_call_str(const string &container, const vector_string &pexprs) const;
+
+  string
+  get_parameter_expr(int n, const vector_string &pexprs) const;
+
+  bool
+  setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface);
+};
+
+#endif

+ 93 - 0
dtool/src/interrogate/functionWriter.cxx

@@ -0,0 +1,93 @@
+// Filename: functionWriter.cxx
+// Created by:  drose (14Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "functionWriter.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriter::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+FunctionWriter::
+FunctionWriter() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriter::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+FunctionWriter::
+~FunctionWriter() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriter::get_name
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+const string &FunctionWriter::
+get_name() const {
+  return _name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriter::compare_to
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+int FunctionWriter::
+compare_to(const FunctionWriter &other) const {
+  // Lexicographical string comparison.
+
+  string::const_iterator n1, n2;
+  n1 = _name.begin();
+  n2 = other._name.begin();
+  while (n1 != _name.end() && n2 != other._name.end()) {
+    if (*n1 != *n2) {
+      return *n1 - *n2;
+    }
+    ++n1;
+    ++n2;
+  }
+  if (n1 != _name.end()) {
+    return -1;
+  }
+  if (n2 != other._name.end()) {
+    return 1;
+  }
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriter::write_prototype
+//       Access: Public, Virtual
+//  Description: Outputs the prototype for the function.
+////////////////////////////////////////////////////////////////////
+void FunctionWriter::
+write_prototype(ostream &) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriter::write_code
+//       Access: Public, Virtual
+//  Description: Outputs the code for the function.
+////////////////////////////////////////////////////////////////////
+void FunctionWriter::
+write_code(ostream &) {
+}

+ 47 - 0
dtool/src/interrogate/functionWriter.h

@@ -0,0 +1,47 @@
+// Filename: functionWriter.h
+// Created by:  drose (14Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef FUNCTIONWRITER_H
+#define FUNCTIONWRITER_H
+
+#include "dtoolbase.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : FunctionWriter
+// Description : This is an abstract class that can be used by the
+//               various WrapperBuilders to indicate a static helper
+//               function or variable that needs to be written to the
+//               generated source file before the code for the
+//               WrapperBuilders.
+////////////////////////////////////////////////////////////////////
+class FunctionWriter {
+public:
+  FunctionWriter();
+  virtual ~FunctionWriter();
+
+  const string &get_name() const;
+  virtual int compare_to(const FunctionWriter &other) const;
+
+  virtual void write_prototype(ostream &out);
+  virtual void write_code(ostream &out);
+
+protected:
+  string _name;
+};
+
+#endif

+ 117 - 0
dtool/src/interrogate/functionWriterPtrFromPython.cxx

@@ -0,0 +1,117 @@
+// Filename: functionWriterPtrFromPython.cxx
+// Created by:  drose (14Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "functionWriterPtrFromPython.h"
+#include "typeManager.h"
+#include "interrogateBuilder.h"
+#include "interrogate.h"
+
+#include "cppPointerType.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrFromPython::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+FunctionWriterPtrFromPython::
+FunctionWriterPtrFromPython(CPPType *type) {
+  _type = TypeManager::unwrap_const(TypeManager::unwrap_pointer(type));
+  _name = 
+    "from_python_" + 
+    InterrogateBuilder::clean_identifier(_type->get_local_name(&parser));
+
+  _pointer_type = new CPPPointerType(_type);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrFromPython::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+FunctionWriterPtrFromPython::
+~FunctionWriterPtrFromPython() {
+  delete _pointer_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrFromPython::write_prototype
+//       Access: Public, Virtual
+//  Description: Outputs the prototype for the function.
+////////////////////////////////////////////////////////////////////
+void FunctionWriterPtrFromPython::
+write_prototype(ostream &out) {
+  CPPType *ppointer = new CPPPointerType(_pointer_type);
+
+  out << "static int " << _name << "(PyObject *obj, ";
+  ppointer->output_instance(out, "addr", &parser);
+  out << ");\n";
+  
+  delete ppointer;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrFromPython::write_code
+//       Access: Public, Virtual
+//  Description: Outputs the code for the function.
+////////////////////////////////////////////////////////////////////
+void FunctionWriterPtrFromPython::
+write_code(ostream &out) {
+  CPPType *ppointer = new CPPPointerType(_pointer_type);
+
+  out << "static int\n"
+      << _name << "(PyObject *obj, ";
+  ppointer->output_instance(out, "addr", &parser);
+  out << ") {\n"
+      << "  if (obj != (PyObject *)NULL && PyInstance_Check(obj)) {\n"
+    //      << "    PyClassObject *in_class = ((PyInstanceObject *)obj)->in_class;\n"
+      << "    PyObject *in_dict = ((PyInstanceObject *)obj)->in_dict;\n"
+      << "    if (in_dict != (PyObject *)NULL && PyDict_Check(in_dict)) {\n"
+      << "      PyObject *thisobj = PyDict_GetItemString(in_dict, \"this\");\n"
+      << "      if (thisobj != (PyObject *)NULL && PyInt_Check(thisobj)) {\n"
+      << "        (*addr) = ("
+      << _pointer_type->get_local_name(&parser) << ")PyInt_AsLong(thisobj);\n"
+      << "        return 1;\n"
+      << "      }\n"
+      << "    }\n"
+      << "  }\n"
+      << "  return 0;\n"
+      << "}\n\n";
+  
+  delete ppointer;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrFromPython::get_type
+//       Access: Public
+//  Description: Returns the type that represents the actual data type.
+////////////////////////////////////////////////////////////////////
+CPPType *FunctionWriterPtrFromPython::
+get_type() const {
+  return _type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrFromPython::get_pointer_type
+//       Access: Public
+//  Description: Returns the type that represents a pointer to the
+//               data type.
+////////////////////////////////////////////////////////////////////
+CPPType *FunctionWriterPtrFromPython::
+get_pointer_type() const {
+  return _pointer_type;
+}

+ 48 - 0
dtool/src/interrogate/functionWriterPtrFromPython.h

@@ -0,0 +1,48 @@
+// Filename: functionWriterPtrFromPython.h
+// Created by:  drose (14Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef FUNCTIONWRITERPTRFROMPYTHON_H
+#define FUNCTIONWRITERPTRFROMPYTHON_H
+
+#include "functionWriter.h"
+
+class CPPType;
+
+////////////////////////////////////////////////////////////////////
+//       Class : FunctionWriterPtrFromPython
+// Description : This specialization of FunctionWriter generates a
+//               function that converts a PyObject pointer
+//               representing a class wrapper object to the
+//               corresponding C++ pointer.
+////////////////////////////////////////////////////////////////////
+class FunctionWriterPtrFromPython : public FunctionWriter {
+public:
+  FunctionWriterPtrFromPython(CPPType *type);
+  virtual ~FunctionWriterPtrFromPython();
+
+  virtual void write_prototype(ostream &out);
+  virtual void write_code(ostream &out);
+  CPPType *get_type() const;
+  CPPType *get_pointer_type() const;
+
+private:
+  CPPType *_type;
+  CPPType *_pointer_type;
+};
+
+#endif

+ 96 - 0
dtool/src/interrogate/functionWriterPtrToPython.cxx

@@ -0,0 +1,96 @@
+// Filename: functionWriterPtrToPython.cxx
+// Created by:  drose (14Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "functionWriterPtrToPython.h"
+#include "typeManager.h"
+#include "interrogateBuilder.h"
+#include "interrogate.h"
+#include "interfaceMakerPythonObj.h"
+
+#include "cppPointerType.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrToPython::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+FunctionWriterPtrToPython::
+FunctionWriterPtrToPython(CPPType *type) {
+  _type = TypeManager::unwrap_const(TypeManager::unwrap_pointer(type));
+  _name = 
+    "to_python_" + 
+    InterrogateBuilder::clean_identifier(_type->get_local_name(&parser));
+
+  _pointer_type = new CPPPointerType(_type);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrToPython::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+FunctionWriterPtrToPython::
+~FunctionWriterPtrToPython() {
+  delete _pointer_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrToPython::write_prototype
+//       Access: Public, Virtual
+//  Description: Outputs the prototype for the function.
+////////////////////////////////////////////////////////////////////
+void FunctionWriterPtrToPython::
+write_prototype(ostream &out) {
+  out << "static PyObject *" << _name << "(";
+  _pointer_type->output_instance(out, "addr", &parser);
+  out << ", int caller_manages);\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrToPython::write_code
+//       Access: Public, Virtual
+//  Description: Outputs the code for the function.
+////////////////////////////////////////////////////////////////////
+void FunctionWriterPtrToPython::
+write_code(ostream &out) {
+  string classobj_func = InterfaceMakerPythonObj::get_builder_name(_type);
+  out << "static PyObject *\n"
+      << _name << "(";
+  _pointer_type->output_instance(out, "addr", &parser);
+  out << ", int caller_manages) {\n"
+      << "  PyObject *" << classobj_func << "();\n"
+      << "  PyObject *classobj = " << classobj_func << "();\n"
+      << "  PyInstanceObject *instance = (PyInstanceObject *)PyInstance_New(classobj, (PyObject *)NULL, (PyObject *)NULL);\n"
+      << "  if (instance != (PyInstanceObject *)NULL) {\n"
+      << "    PyObject *thisptr = PyInt_FromLong((long)addr);\n"
+      << "    PyDict_SetItemString(instance->in_dict, \"this\", thisptr);\n"
+      << "  }\n"
+      << "  return (PyObject *)instance;\n"
+      << "}\n\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriterPtrToPython::get_pointer_type
+//       Access: Public
+//  Description: Returns the type that represents a pointer to the
+//               data type.
+////////////////////////////////////////////////////////////////////
+CPPType *FunctionWriterPtrToPython::
+get_pointer_type() const {
+  return _pointer_type;
+}

+ 46 - 0
dtool/src/interrogate/functionWriterPtrToPython.h

@@ -0,0 +1,46 @@
+// Filename: functionWriterPtrToPython.h
+// Created by:  drose (14Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef FUNCTIONWRITERPTRTOPYTHON_H
+#define FUNCTIONWRITERPTRTOPYTHON_H
+
+#include "functionWriter.h"
+
+class CPPType;
+
+////////////////////////////////////////////////////////////////////
+//       Class : FunctionWriterPtrToPython
+// Description : This specialization of FunctionWriter generates a
+//               function that generates a PyObject class wrapper
+//               object around the corresponding C++ pointer.
+////////////////////////////////////////////////////////////////////
+class FunctionWriterPtrToPython : public FunctionWriter {
+public:
+  FunctionWriterPtrToPython(CPPType *type);
+  virtual ~FunctionWriterPtrToPython();
+
+  virtual void write_prototype(ostream &out);
+  virtual void write_code(ostream &out);
+  CPPType *get_pointer_type() const;
+
+private:
+  CPPType *_type;
+  CPPType *_pointer_type;
+};
+
+#endif

+ 91 - 0
dtool/src/interrogate/functionWriters.cxx

@@ -0,0 +1,91 @@
+// Filename: functionWriters.cxx
+// Created by:  drose (14Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "functionWriters.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriters::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+FunctionWriters::
+FunctionWriters() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriters::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+FunctionWriters::
+~FunctionWriters() {
+  Writers::iterator wi;
+  for (wi = _writers.begin(); wi != _writers.end(); ++wi) {
+    delete (*wi);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriters::add_writer
+//       Access: Public
+//  Description: Adds the indicated FunctionWriter to the set of
+//               functions to be written, unless there is already a
+//               matching FunctionWriter.
+//
+//               The return value is the FunctionWriter pointer that
+//               was added to the set, which may be the same pointer
+//               or a previously-allocated (but equivalent) pointer.
+////////////////////////////////////////////////////////////////////
+FunctionWriter *FunctionWriters::
+add_writer(FunctionWriter *writer) {
+  pair<Writers::iterator, bool> result = _writers.insert(writer);
+  if (!result.second) {
+    // Already there; delete the pointer.
+    delete writer;
+  }
+
+  // Return the pointer that is in the set.
+  return *result.first;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriters::write_prototypes
+//       Access: Public
+//  Description: Generates prototypes for all of the functions.
+////////////////////////////////////////////////////////////////////
+void FunctionWriters::
+write_prototypes(ostream &out) {
+  Writers::iterator wi;
+  for (wi = _writers.begin(); wi != _writers.end(); ++wi) {
+    FunctionWriter *writer = (*wi);
+    (*wi)->write_prototype(out);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FunctionWriters::write_code
+//       Access: Public
+//  Description: Generates all of the functions.
+////////////////////////////////////////////////////////////////////
+void FunctionWriters::
+write_code(ostream &out) {
+  Writers::iterator wi;
+  for (wi = _writers.begin(); wi != _writers.end(); ++wi) {
+    (*wi)->write_code(out);
+  }
+}

+ 56 - 0
dtool/src/interrogate/functionWriters.h

@@ -0,0 +1,56 @@
+// Filename: functionWriters.h
+// Created by:  drose (14Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef FUNCTIONWRITERS_H
+#define FUNCTIONWRITERS_H
+
+#include "dtoolbase.h"
+#include "functionWriter.h"
+
+#include <set.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : FunctionWriters
+// Description : A set of zero or more FunctionWriter pointers
+//               accumulated by the various WrapperBuilder objects
+//               that are generating code for one particular output
+//               source file.
+////////////////////////////////////////////////////////////////////
+class FunctionWriters {
+public:
+  FunctionWriters();
+  ~FunctionWriters();
+
+  FunctionWriter *add_writer(FunctionWriter *writer);
+
+  void write_prototypes(ostream &out);
+  void write_code(ostream &out);
+
+protected:
+  class IndirectCompareTo {
+  public:
+    bool operator () (const FunctionWriter *a, const FunctionWriter *b) const {
+      return a->compare_to(*b) < 0;
+    }
+  };
+
+  typedef set<FunctionWriter *, IndirectCompareTo> Writers;
+  Writers _writers;
+};
+
+#endif

+ 751 - 0
dtool/src/interrogate/interfaceMaker.cxx

@@ -0,0 +1,751 @@
+// Filename: interfaceMaker.cxx
+// Created by:  drose (19Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "interfaceMaker.h"
+#include "interrogateBuilder.h"
+#include "typeManager.h"
+#include "interrogate.h"
+#include "functionRemap.h"
+#include "parameterRemap.h"
+#include "parameterRemapThis.h"
+#include "parameterRemapUnchanged.h"
+#include "parameterRemapReferenceToPointer.h"
+#include "parameterRemapConcreteToPointer.h"
+#include "parameterRemapEnumToInt.h"
+#include "parameterRemapConstToNonConst.h"
+#include "parameterRemapReferenceToConcrete.h"
+#include "parameterRemapCharStarToString.h"
+#include "parameterRemapBasicStringToString.h"
+#include "parameterRemapBasicStringRefToString.h"
+#include "parameterRemapPTToPointer.h"
+
+#include "interrogateDatabase.h"
+#include "interrogateManifest.h"
+#include "interrogateElement.h"
+#include "cppFunctionType.h"
+#include "cppParameterList.h"
+#include "notify.h"
+
+static InterrogateType dummy_type;
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::Function::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMaker::Function::
+Function(const string &name,
+         const InterrogateType &itype,
+         const InterrogateFunction &ifunc) :
+  _name(name),
+  _itype(itype),
+  _ifunc(ifunc)
+{
+  _has_this = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::Function::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMaker::Function::
+~Function() {
+  Remaps::iterator ri;
+  for (ri = _remaps.begin(); ri != _remaps.end(); ++ri) {
+    delete (*ri);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::Object::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMaker::Object::
+Object(const InterrogateType &itype) :
+  _itype(itype)
+{
+  _destructor = (Function *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::Object::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMaker::Object::
+~Object() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMaker::
+InterfaceMaker(InterrogateModuleDef *def) :
+  _def(def)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMaker::
+~InterfaceMaker() {
+  Objects::iterator oi;
+  for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
+    Object *object = (*oi).second;
+    delete object;
+  }
+  Functions::iterator fi;
+  for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
+    delete (*fi);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::generate_wrappers
+//       Access: Public, Virtual
+//  Description: Walks through the set of functions in the database
+//               and generates wrappers for each function, storing
+//               these in the database.  No actual code should be
+//               output yet; this just updates the database with the
+//               wrapper information.
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+generate_wrappers() {
+  InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
+
+  // We use a while loop rather than a simple for loop, because we
+  // might increase the number of types recursively during the
+  // traversal.
+  int ti = 0;
+  while (ti < idb->get_num_all_types()) {
+    TypeIndex type_index = idb->get_all_type(ti);
+    record_object(type_index);
+    ++ti;
+  }
+
+  int num_functions = idb->get_num_global_functions();
+  for (int fi = 0; fi < num_functions; fi++) {
+    FunctionIndex func_index = idb->get_global_function(fi);
+    record_function(dummy_type, func_index);
+  }    
+
+  int num_manifests = idb->get_num_global_manifests();
+  for (int mi = 0; mi < num_manifests; mi++) {
+    ManifestIndex manifest_index = idb->get_global_manifest(mi);
+    const InterrogateManifest &iman = idb->get_manifest(manifest_index);
+    if (iman.has_getter()) {
+      FunctionIndex func_index = iman.get_getter();
+      record_function(dummy_type, func_index);
+    }
+  }    
+
+  int num_elements = idb->get_num_global_elements();
+  for (int ei = 0; ei < num_elements; ei++) {
+    ElementIndex element_index = idb->get_global_element(ei);
+    const InterrogateElement &ielement = idb->get_element(element_index);
+    if (ielement.has_getter()) {
+      FunctionIndex func_index = ielement.get_getter();
+      record_function(dummy_type, func_index);
+    }
+    if (ielement.has_setter()) {
+      FunctionIndex func_index = ielement.get_setter();
+      record_function(dummy_type, func_index);
+    }
+  }    
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::write_includes
+//       Access: Public, Virtual
+//  Description: Generates the list of #include ... whatever that's
+//               required by this particular interface to the
+//               indicated output stream.
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+write_includes(ostream &) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::write_prototypes
+//       Access: Public, Virtual
+//  Description: Generates the list of function prototypes
+//               corresponding to the functions that will be output in
+//               write_functions().
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+write_prototypes(ostream &out) {
+  _function_writers.write_prototypes(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::write_functions
+//       Access: Public, Virtual
+//  Description: Generates the list of functions that are appropriate
+//               for this interface.
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+write_functions(ostream &out) {
+  _function_writers.write_code(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::write_module
+//       Access: Public, Virtual
+//  Description: Generates whatever additional code is required to
+//               support a module file.
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+write_module(ostream &, InterrogateModuleDef *) {
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::remap_parameter
+//       Access: Public, Virtual
+//  Description: Allocates a new ParameterRemap object suitable to the
+//               indicated parameter type.  If struct_type is
+//               non-NULL, it is the type of the enclosing class for
+//               the function (method) in question.
+//
+//               The return value is a newly-allocated ParameterRemap
+//               object, if the parameter type is acceptable, or NULL
+//               if the parameter type cannot be handled.
+////////////////////////////////////////////////////////////////////
+ParameterRemap *InterfaceMaker::
+remap_parameter(CPPType *struct_type, CPPType *param_type) {
+  if (convert_strings) {
+    if (TypeManager::is_char_pointer(param_type)) {
+      return new ParameterRemapCharStarToString(param_type);
+    }
+
+    // If we're exporting a method of basic_string<char> itself, don't
+    // convert basic_string<char>'s to atomic strings.
+
+    if (struct_type == (CPPType *)NULL ||
+        !TypeManager::is_basic_string_char(struct_type)) {
+      if (TypeManager::is_basic_string_char(param_type)) {
+        return new ParameterRemapBasicStringToString(param_type);
+
+      } else if (TypeManager::is_const_ref_to_basic_string_char(param_type)) {
+        return new ParameterRemapBasicStringRefToString(param_type);
+      }
+    }
+  }
+
+  if (manage_reference_counts) {
+    if (TypeManager::is_pointer_to_base(param_type) ||
+        TypeManager::is_const_ref_to_pointer_to_base(param_type)) {
+      CPPType *pt_type = TypeManager::unwrap_reference(param_type);
+
+      // Don't convert PointerTo<>'s to pointers for methods of the
+      // PointerTo itself!
+      if (struct_type == (CPPType *)NULL ||
+          !(pt_type->get_local_name(&parser) == struct_type->get_local_name(&parser))) {
+        return new ParameterRemapPTToPointer(param_type);
+      }
+    }
+  }
+
+  if (TypeManager::is_reference(param_type)) {
+    return new ParameterRemapReferenceToPointer(param_type);
+
+  } else if (TypeManager::is_struct(param_type)) {
+    return new ParameterRemapConcreteToPointer(param_type);
+
+    /*
+  } else if (TypeManager::is_enum(param_type) || TypeManager::is_const_ref_to_enum(param_type)) {
+    return new ParameterRemapEnumToInt(param_type);
+    */
+
+  } else if (TypeManager::is_const_simple(param_type)) {
+    return new ParameterRemapConstToNonConst(param_type);
+
+  } else if (TypeManager::is_const_ref_to_simple(param_type)) {
+    return new ParameterRemapReferenceToConcrete(param_type);
+
+  } else if (TypeManager::is_pointer(param_type) || TypeManager::is_simple(param_type)) {
+    return new ParameterRemapUnchanged(param_type);
+
+  } else {
+    // Here's something we have a problem with.
+    return (ParameterRemap *)NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::synthesize_this_parameter
+//       Access: Public, Virtual
+//  Description: This method should be overridden and redefined to
+//               return true for interfaces that require the implicit
+//               "this" parameter, if present, to be passed as the
+//               first parameter to any wrapper functions.
+////////////////////////////////////////////////////////////////////
+bool InterfaceMaker::
+synthesize_this_parameter() {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::separate_overloading
+//       Access: Public, Virtual
+//  Description: This method should be overridden and redefined to
+//               return true for interfaces that require overloaded
+//               instances of a function to be defined as separate
+//               functions (each with its own hashed name), or false
+//               for interfaces that can support overloading natively,
+//               and thus only require one wrapper function per each
+//               overloaded input function.
+////////////////////////////////////////////////////////////////////
+bool InterfaceMaker::
+separate_overloading() {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::get_function_remaps
+//       Access: Public
+//  Description: Fills up the indicated vector with all of the
+//               FunctionRemap pointers created by this
+//               InterfaceMaker.  It is the user's responsibility to
+//               empty the vector before calling this function; the
+//               new pointers will simply be added to the end.
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+get_function_remaps(vector<FunctionRemap *> &remaps) {
+  Functions::iterator fi;
+  for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
+    Function *func = (*fi);
+    Function::Remaps::const_iterator ri;
+    for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
+      FunctionRemap *remap = (*ri);
+      remaps.push_back(remap);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::indent
+//       Access: Public, Static
+//  Description:
+////////////////////////////////////////////////////////////////////
+ostream &InterfaceMaker::
+indent(ostream &out, int indent_level) {
+  for (int i = 0; i < indent_level; i++) {
+    out << ' ';
+  }
+  return out;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::make_function_remap
+//       Access: Protected, Virtual
+//  Description: Creates a FunctionRemap object corresponding to the
+//               particular function wrapper.
+////////////////////////////////////////////////////////////////////
+FunctionRemap *InterfaceMaker::
+make_function_remap(const InterrogateType &itype,
+                    const InterrogateFunction &ifunc,
+                    CPPInstance *cppfunc, int num_default_parameters) {
+  FunctionRemap *remap = 
+    new FunctionRemap(itype, ifunc, cppfunc, num_default_parameters, this);
+  if (remap->_is_valid) {
+    if (separate_overloading()) {
+      hash_function_signature(remap);
+      remap->_unique_name =
+        get_unique_prefix() + _def->library_hash_name + remap->_hash;
+      remap->_wrapper_name = 
+        get_wrapper_prefix() + _def->library_hash_name + remap->_hash;
+    }
+    return remap;
+  }
+
+  // No such FunctionRemap is valid.  Return NULL.
+  delete remap;
+  return (FunctionRemap *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::get_wrapper_name
+//       Access: Protected, Virtual
+//  Description: Returns the function name that will be used to wrap
+//               the indicated function.
+//
+//               This is the name for the overall wrapper function,
+//               including all of the overloaded instances.
+//               Interfaces that must define a different wrapper for
+//               each FunctionRemap object (i.e. for each instance of
+//               an overloaded function) need not define a name here.
+////////////////////////////////////////////////////////////////////
+string InterfaceMaker::
+get_wrapper_name(const InterrogateType &itype, 
+                 const InterrogateFunction &ifunc,
+                 FunctionIndex func_index) {
+  string func_name = ifunc.get_scoped_name();
+  string clean_name = InterrogateBuilder::clean_identifier(func_name);
+
+  ostringstream new_name;
+  new_name << get_wrapper_prefix() << clean_name << "_" << func_index;
+  return new_name.str();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::get_wrapper_prefix
+//       Access: Protected, Virtual
+//  Description: Returns the prefix string used to generate wrapper
+//               function names.
+////////////////////////////////////////////////////////////////////
+string InterfaceMaker::
+get_wrapper_prefix() {
+  return "xx_";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::get_unique_prefix
+//       Access: Protected, Virtual
+//  Description: Returns the prefix string used to generate unique
+//               symbolic names, which are not necessarily C-callable
+//               function names.
+////////////////////////////////////////////////////////////////////
+string InterfaceMaker::
+get_unique_prefix() {
+  return "x";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::record_function
+//       Access: Protected
+//  Description: Records the indicated function, along with all of its
+//               FunctionRemap flavors and FunctionWriter helpers, for
+//               future output.  Returns the new Function pointer.
+////////////////////////////////////////////////////////////////////
+InterfaceMaker::Function *InterfaceMaker::
+record_function(const InterrogateType &itype, FunctionIndex func_index) {
+  InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
+  const InterrogateFunction &ifunc = idb->get_function(func_index);
+
+  string wrapper_name = get_wrapper_name(itype, ifunc, func_index);
+  Function *func = new Function(wrapper_name, itype, ifunc);
+  _functions.push_back(func);
+
+  // Now get all the valid FunctionRemaps for the function.
+  InterrogateFunction::Instances::const_iterator ii;
+  for (ii = ifunc._instances.begin();
+       ii != ifunc._instances.end();
+       ++ii) {
+    CPPInstance *cppfunc = (*ii).second;
+    CPPFunctionType *ftype = cppfunc->_type->as_function_type();
+    int max_default_parameters = 0;
+
+    if (separate_overloading()) {
+      // Count up the number of default parameters this function might
+      // take.
+      CPPParameterList *parameters = ftype->_parameters;
+      CPPParameterList::Parameters::reverse_iterator pi;
+      for (pi = parameters->_parameters.rbegin(); 
+           pi != parameters->_parameters.rend();
+           ++pi) {
+        CPPInstance *param = (*pi);
+        if (param->_initializer != (CPPExpression *)NULL) {
+          // This parameter has a default value.
+          max_default_parameters++;
+        } else {
+          // The first parameter without a default value ends the search.
+          break;
+        }
+      }
+    }
+
+    // Now make a different wrapper for each combination of default
+    // parameters.  This will happen only if separate_overloading(),
+    // tested above, returned true; otherwise, max_default_parameters
+    // will be 0 and the loop will only be traversed once.
+    for (int num_default_parameters = 0; 
+         num_default_parameters <= max_default_parameters;
+         num_default_parameters++) {
+      FunctionRemap *remap = 
+        make_function_remap(itype, ifunc, cppfunc, num_default_parameters);
+      if (remap != (FunctionRemap *)NULL) {
+        func->_remaps.push_back(remap);
+        
+        // If *any* of the variants of this function has a "this"
+        // pointer, the entire set of functions is deemed to have a
+        // "this" pointer.
+        if (remap->_has_this) {
+          func->_has_this = true;
+        }
+        
+        // Make a wrapper for the function.
+        FunctionWrapperIndex wrapper_index = 
+          remap->make_wrapper_entry(func_index);
+        if (wrapper_index != 0) {
+          InterrogateFunction &mod_ifunc = idb->update_function(func_index);
+          record_function_wrapper(mod_ifunc, wrapper_index);
+        }
+      }
+    }
+  }
+
+  return func;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::record_function_wrapper
+//       Access: Protected, Virtual
+//  Description: Associates the function wrapper with its function in
+//               the appropriate structures in the database.
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+record_function_wrapper(InterrogateFunction &, FunctionWrapperIndex) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::record_object
+//       Access: Protected
+//  Description: Records the indicated type, which may be a struct
+//               type, along with all of its associated methods, if
+//               any.
+////////////////////////////////////////////////////////////////////
+InterfaceMaker::Object *InterfaceMaker::
+record_object(TypeIndex type_index) {
+  if (type_index == 0) {
+    // An invalid type.
+    return (Object *)NULL;
+  }
+
+  Objects::iterator oi = _objects.find(type_index);
+  if (oi != _objects.end()) {
+    // The object has previously been recorded.
+    return (*oi).second;
+  }
+
+  InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
+  const InterrogateType &itype = idb->get_type(type_index);    
+
+  Object *object = new Object(itype);
+  bool inserted = _objects.insert(Objects::value_type(type_index, object)).second;
+  assert(inserted);
+
+  Function *function;
+
+  int num_constructors = itype.number_of_constructors();
+  for (int ci = 0; ci < num_constructors; ci++) {
+    function = record_function(itype, itype.get_constructor(ci));
+    object->_constructors.push_back(function);
+  }
+
+  if (itype.has_destructor() && !itype.destructor_is_inherited()) {
+    function = record_function(itype, itype.get_destructor());
+    object->_destructor = function;
+  }
+  
+  int num_methods = itype.number_of_methods();
+  int mi;
+  for (mi = 0; mi < num_methods; mi++) {
+    function = record_function(itype, itype.get_method(mi));
+    object->_methods.push_back(function);
+  }
+  
+  int num_casts = itype.number_of_casts();
+  for (mi = 0; mi < num_casts; mi++) {
+    function = record_function(itype, itype.get_cast(mi));
+    object->_methods.push_back(function);
+  }
+  
+  int num_derivations = itype.number_of_derivations();
+  for (int di = 0; di < num_derivations; di++) {
+    if (itype.derivation_has_upcast(di)) {
+      record_function(itype, itype.derivation_get_upcast(di));
+    }
+    if (itype.derivation_has_downcast(di)) {
+      record_function(itype, itype.derivation_get_downcast(di));
+    }
+  }
+
+  int num_elements = itype.number_of_elements();
+  for (int ei = 0; ei < num_elements; ei++) {
+    ElementIndex element_index = itype.get_element(ei);
+    const InterrogateElement &ielement = idb->get_element(element_index);
+    if (ielement.has_getter()) {
+      FunctionIndex func_index = ielement.get_getter();
+      record_function(itype, func_index);
+    }
+    if (ielement.has_setter()) {
+      FunctionIndex func_index = ielement.get_setter();
+      record_function(itype, func_index);
+    }
+  }    
+
+  int num_nested = itype.number_of_nested_types();
+  for (int ni = 0; ni < num_nested; ni++) {
+    TypeIndex nested_index = itype.get_nested_type(ni);
+    record_object(nested_index);
+  }
+
+  return object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::manage_return_value
+//       Access: Protected
+//  Description: Does any additional processing that we might want to
+//               do on the return value for the function, just before
+//               we return it.  Returns the string representing the
+//               new return value after processing.
+////////////////////////////////////////////////////////////////////
+string InterfaceMaker::
+manage_return_value(ostream &out, int indent_level,
+                    FunctionRemap *remap, const string &return_expr) const {
+  if (remap->_manage_reference_count) {
+    // If we're managing reference counts, and we're about to return a
+    // reference countable object, then increment its count.
+    if (return_expr == "return_value") {
+      // If the expression is just a variable name, we can just ref it
+      // directly.
+      output_ref(out, indent_level, remap, return_expr);
+      return return_expr;
+
+    } else {
+      // Otherwise, we should probably assign it to a temporary first,
+      // so we don't invoke the function twice or something.
+      CPPType *type = remap->_return_type->get_temporary_type();
+      indent(out, indent_level);
+      type->output_instance(out, "refcount", &parser);
+      out << " = " << return_expr << ";\n";
+
+      indent(out, indent_level)
+        << "if (" << return_expr << " != ("
+        << remap->_return_type->get_new_type()->get_local_name(&parser) << ")0) {\n";
+      indent(out, indent_level + 2)
+        << return_expr << "->ref();\n";
+      indent(out, indent_level)
+        << "}\n";
+      output_ref(out, indent_level, remap, "refcount");
+      return remap->_return_type->temporary_to_return("refcount");
+    }
+  }
+
+  // Otherwise, just return the expression unchanged.
+  return return_expr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::output_ref
+//       Access: Protected
+//  Description: Outputs the code to increment the reference count for
+//               the indicated variable name.
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+output_ref(ostream &out, int indent_level, FunctionRemap *remap, 
+           const string &varname) const {
+  if (remap->_type == FunctionRemap::T_constructor ||
+      remap->_type == FunctionRemap::T_typecast) {
+    // In either of these cases, we can safely assume the pointer will
+    // never be NULL.
+    indent(out, indent_level)
+      << varname << "->ref();\n";
+
+  } else {
+    // However, in the general case, we have to check for that before
+    // we attempt to ref it.
+
+    indent(out, indent_level)
+      << "if (" << varname << " != ("
+      << remap->_return_type->get_new_type()->get_local_name(&parser) << ")0) {\n";
+    indent(out, indent_level + 2)
+      << varname << "->ref();\n";
+    indent(out, indent_level)
+      << "}\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::hash_function_signature
+//       Access: Protected
+//  Description: Generates a unique string that corresponds to the
+//               function signature for the indicated FunctionRemap
+//               object, and stores the generated string in the _hash
+//               member of the FunctionRemap.
+////////////////////////////////////////////////////////////////////
+void InterfaceMaker::
+hash_function_signature(FunctionRemap *remap) {
+  string hash = InterrogateBuilder::hash_string(remap->_function_signature, 5);
+
+  // Now make sure we don't have another function with the same hash.
+  WrappersByHash::iterator hi;
+  hi = _wrappers_by_hash.find(hash);
+  if (hi == _wrappers_by_hash.end()) {
+    // No other name; we're in the clear.
+    _wrappers_by_hash[hash] = remap;
+    remap->_hash = hash;
+    return;
+  }
+
+  if ((*hi).second != (FunctionRemap *)NULL &&
+      (*hi).second->_function_signature == remap->_function_signature) {
+    // The same function signature has already appeared.  This
+    // shouldn't happen.
+    nout << "Internal error!  Function signature "
+         << remap->_function_signature << " repeated!\n";
+    remap->_hash = hash;
+    abort(); 
+    return;
+  }
+
+  // We have a conflict.  Extend both strings to resolve the
+  // ambiguity.
+  if ((*hi).second != (FunctionRemap *)NULL) {
+    FunctionRemap *other_remap = (*hi).second;
+    (*hi).second = (FunctionRemap *)NULL;
+    other_remap->_hash +=
+      InterrogateBuilder::hash_string(other_remap->_function_signature, 11);
+    bool inserted = _wrappers_by_hash.insert
+      (WrappersByHash::value_type(other_remap->_hash, other_remap)).second;
+    if (!inserted) {
+      nout << "Internal error!  Hash " << other_remap->_hash
+           << " already appears!\n";
+    }
+  }
+
+  hash += InterrogateBuilder::hash_string(remap->_function_signature, 11);
+  bool inserted = _wrappers_by_hash.insert
+    (WrappersByHash::value_type(hash, remap)).second;
+
+  if (!inserted) {
+    // Huh.  We still have a conflict.  This should be extremely rare.
+    // Well, just tack on a letter until it's resolved.
+    string old_hash = hash;
+    for (char ch = 'a'; ch <= 'z' && !inserted; ch++) {
+      hash = old_hash + ch;
+      inserted = _wrappers_by_hash.insert
+        (WrappersByHash::value_type(hash, remap)).second;
+    }
+    if (!inserted) {
+      nout << "Internal error!  Too many conflicts with hash "
+           << hash << "\n";
+    }
+  }
+
+  remap->_hash = hash;
+}

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

@@ -0,0 +1,148 @@
+// Filename: interfaceMaker.h
+// Created by:  drose (19Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef INTERFACEMAKER_H
+#define INTERFACEMAKER_H
+
+#include "dtoolbase.h"
+
+#include "interrogate_interface.h"
+#include "interrogate_request.h"
+#include "functionWriters.h"
+
+#include <vector>
+#include <map>
+
+class FunctionRemap;
+class ParameterRemap;
+class CPPType;
+class CPPInstance;
+class InterrogateBuilder;
+class InterrogateType;
+class InterrogateFunction;
+
+////////////////////////////////////////////////////////////////////
+//       Class : InterfaceMaker
+// Description : This is an abstract base class that defines how to
+//               generate code that can be called from an external
+//               language (like Python or Squeak) and that can call
+//               into Panda.
+//
+//               The specializations of this class like
+//               InterfaceMakerPython and InterfaceMakerC will
+//               generate the actual wrappers for the various language
+//               calling conventions.
+////////////////////////////////////////////////////////////////////
+class InterfaceMaker {
+public:
+  InterfaceMaker(InterrogateModuleDef *def);
+  virtual ~InterfaceMaker();
+
+  virtual void generate_wrappers();
+
+  virtual void write_includes(ostream &out);
+  virtual void write_prototypes(ostream &out);
+  virtual void write_functions(ostream &out);
+
+  virtual void write_module(ostream &out, InterrogateModuleDef *def);
+
+  virtual ParameterRemap *
+  remap_parameter(CPPType *struct_type, CPPType *param_type);
+
+  virtual bool synthesize_this_parameter();
+  virtual bool separate_overloading();
+
+  void get_function_remaps(vector<FunctionRemap *> &remaps);
+
+  static ostream &indent(ostream &out, int indent_level);
+
+protected:
+  class Function {
+  public:
+    Function(const string &name,
+             const InterrogateType &itype,
+             const InterrogateFunction &ifunc);
+    ~Function();
+
+    string _name;
+    const InterrogateType &_itype;
+    const InterrogateFunction &_ifunc;
+    typedef vector<FunctionRemap *> Remaps;
+    Remaps _remaps;
+    bool _has_this;
+  };
+  typedef vector<Function *> Functions;
+  Functions _functions;
+
+  class Object {
+  public:
+    Object(const InterrogateType &itype);
+    ~Object();
+
+    void add_method(Function *method);
+
+    const InterrogateType &_itype;
+    Functions _constructors;
+    Functions _methods;
+    Function *_destructor;
+  };
+  typedef map<TypeIndex, Object *> Objects;
+  Objects _objects;
+
+  typedef map<string, FunctionRemap *> WrappersByHash;
+  WrappersByHash _wrappers_by_hash;
+
+  virtual FunctionRemap *
+  make_function_remap(const InterrogateType &itype,
+                      const InterrogateFunction &ifunc,
+                      CPPInstance *cppfunc, int num_default_parameters);
+
+  virtual string
+  get_wrapper_name(const InterrogateType &itype, 
+                   const InterrogateFunction &ifunc,
+                   FunctionIndex func_index);
+  virtual string get_wrapper_prefix();
+  virtual string get_unique_prefix();
+  
+  Function *
+  record_function(const InterrogateType &itype, FunctionIndex func_index);
+
+  virtual void
+  record_function_wrapper(InterrogateFunction &ifunc, 
+                          FunctionWrapperIndex wrapper_index);
+
+  Object *
+  record_object(TypeIndex type_index);
+
+  void hash_function_signature(FunctionRemap *remap);
+  
+
+  string
+  manage_return_value(ostream &out, int indent_level,
+                      FunctionRemap *remap, const string &return_expr) const;
+
+  void output_ref(ostream &out, int indent_level, FunctionRemap *remap, 
+                  const string &varname) const;
+
+protected:
+  InterrogateModuleDef *_def;
+
+  FunctionWriters _function_writers;
+};
+
+#endif

+ 242 - 0
dtool/src/interrogate/interfaceMakerC.cxx

@@ -0,0 +1,242 @@
+// Filename: interfaceMakerC.cxx
+// Created by:  drose (25Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "interfaceMakerC.h"
+#include "interrogateBuilder.h"
+#include "interrogate.h"
+#include "functionRemap.h"
+#include "parameterRemapUnchanged.h"
+#include "typeManager.h"
+
+#include "interrogateDatabase.h"
+#include "interrogateType.h"
+#include "interrogateFunction.h"
+#include "cppFunctionType.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMakerC::
+InterfaceMakerC(InterrogateModuleDef *def) :
+  InterfaceMaker(def)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMakerC::
+~InterfaceMakerC() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::write_prototypes
+//       Access: Public, Virtual
+//  Description: Generates the list of function prototypes
+//               corresponding to the functions that will be output in
+//               write_functions().
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerC::
+write_prototypes(ostream &out) {
+  Functions::iterator fi;
+  for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
+    Function *func = (*fi);
+    write_prototype_for(out, func);
+  }
+
+  out << "\n";
+  InterfaceMaker::write_prototypes(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::write_functions
+//       Access: Public, Virtual
+//  Description: Generates the list of functions that are appropriate
+//               for this interface.  This function is called *before*
+//               write_prototypes(), above.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerC::
+write_functions(ostream &out) {
+  Functions::iterator fi;
+  for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
+    Function *func = (*fi);
+    write_function_for(out, func);
+  }
+
+  InterfaceMaker::write_functions(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::synthesize_this_parameter
+//       Access: Public, Virtual
+//  Description: This method should be overridden and redefined to
+//               return true for interfaces that require the implicit
+//               "this" parameter, if present, to be passed as the
+//               first parameter to any wrapper functions.
+////////////////////////////////////////////////////////////////////
+bool InterfaceMakerC::
+synthesize_this_parameter() {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::get_wrapper_prefix
+//       Access: Protected, Virtual
+//  Description: Returns the prefix string used to generate wrapper
+//               function names.
+////////////////////////////////////////////////////////////////////
+string InterfaceMakerC::
+get_wrapper_prefix() {
+  return "_inC";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::get_unique_prefix
+//       Access: Protected, Virtual
+//  Description: Returns the prefix string used to generate unique
+//               symbolic names, which are not necessarily C-callable
+//               function names.
+////////////////////////////////////////////////////////////////////
+string InterfaceMakerC::
+get_unique_prefix() {
+  return "c";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::record_function_wrapper
+//       Access: Protected, Virtual
+//  Description: Associates the function wrapper with its function in
+//               the appropriate structures in the database.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerC::
+record_function_wrapper(InterrogateFunction &ifunc, 
+                        FunctionWrapperIndex wrapper_index) {
+  ifunc._c_wrappers.push_back(wrapper_index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::write_prototype_for
+//       Access: Private
+//  Description: Writes the prototype for the indicated function.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerC::
+write_prototype_for(ostream &out, InterfaceMaker::Function *func) {
+  Function::Remaps::const_iterator ri;
+
+  for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
+    FunctionRemap *remap = (*ri);
+    if (output_function_names) {
+      out << "extern \"C\" ";
+    }
+    write_function_header(out, func, remap, false);
+    out << ";\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::write_function_for
+//       Access: Private
+//  Description: Writes the definition for a function that will call
+//               the indicated C++ function or method.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerC::
+write_function_for(ostream &out, InterfaceMaker::Function *func) {
+  Function::Remaps::const_iterator ri;
+
+  for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
+    FunctionRemap *remap = (*ri);
+    write_function_instance(out, func, remap);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::write_function_instance
+//       Access: Private
+//  Description: Writes out the particular function that handles a
+//               single instance of an overloaded function.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerC::
+write_function_instance(ostream &out, InterfaceMaker::Function *func,
+                        FunctionRemap *remap) {
+  out << "/*\n"
+      << " * C wrapper for\n"
+      << " * ";
+  remap->write_orig_prototype(out, 0);
+  out << "\n"
+      << " */\n";
+    
+  if (!output_function_names) {
+    // If we're not saving the function names, don't export it from
+    // the library.
+    out << "static ";
+  }
+
+  write_function_header(out, func, remap, true);
+  out << " {\n";
+    
+  //  write_spam_message(def_index, out);
+    
+  string return_expr = 
+    remap->call_function(out, 2, true, "param0");
+  return_expr = manage_return_value(out, 2, remap, return_expr);
+  if (!return_expr.empty()) {
+    out << "  return " << return_expr << ";\n";
+  }
+  
+  out << "}\n\n";
+}
+    
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerC::write_function_header
+//       Access: Private
+//  Description: Writes the first line of a function definition,
+//               either for a prototype or a function body.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerC::
+write_function_header(ostream &out, InterfaceMaker::Function *func,
+                      FunctionRemap *remap, bool newline) {
+  if (remap->_void_return) {
+    out << "void";
+  } else {
+    out << remap->_return_type->get_new_type()->get_local_name(&parser);
+  }
+  if (newline) {
+    out << "\n";
+  } else {
+    out << " ";
+  }
+
+  out << remap->_wrapper_name << "(";
+  int pn = 0;
+  if (pn < (int)remap->_parameters.size()) {
+    remap->_parameters[pn]._remap->get_new_type()->
+      output_instance(out, remap->get_parameter_name(pn), &parser);
+    pn++;
+    while (pn < (int)remap->_parameters.size()) {
+      out << ", ";
+      remap->_parameters[pn]._remap->get_new_type()->
+        output_instance(out, remap->get_parameter_name(pn), &parser);
+      pn++;
+    }
+  }
+  out << ")";
+}

+ 62 - 0
dtool/src/interrogate/interfaceMakerC.h

@@ -0,0 +1,62 @@
+// Filename: interfaceMakerC.h
+// Created by:  drose (25Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef INTERFACEMAKERC_H
+#define INTERFACEMAKERC_H
+
+#include "dtoolbase.h"
+
+#include "interfaceMaker.h"
+#include "interrogate_interface.h"
+
+class FunctionRemap;
+
+////////////////////////////////////////////////////////////////////
+//       Class : InterfaceMakerC
+// Description : An InteraceMaker suitable for generating
+//               a series of C-calling-convention functions for
+//               Panda class objects.
+////////////////////////////////////////////////////////////////////
+class InterfaceMakerC : public InterfaceMaker {
+public:
+  InterfaceMakerC(InterrogateModuleDef *def);
+  virtual ~InterfaceMakerC();
+
+  virtual void write_prototypes(ostream &out);
+  virtual void write_functions(ostream &out);
+
+  virtual bool synthesize_this_parameter();
+
+protected:
+  virtual string get_wrapper_prefix();
+  virtual string get_unique_prefix();
+
+  virtual void
+  record_function_wrapper(InterrogateFunction &ifunc, 
+                          FunctionWrapperIndex wrapper_index);
+
+private:
+  void write_prototype_for(ostream &out, Function *func);
+  void write_function_for(ostream &out, Function *func);
+  void write_function_instance(ostream &out, Function *func,
+                               FunctionRemap *remap);
+  void write_function_header(ostream &out, Function *func,
+                             FunctionRemap *remap, bool newline);
+};
+
+#endif

+ 73 - 0
dtool/src/interrogate/interfaceMakerPython.cxx

@@ -0,0 +1,73 @@
+// Filename: interfaceMakerPython.cxx
+// Created by:  drose (21Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "interfaceMakerPython.h"
+#include "interrogate.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPython::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMakerPython::
+InterfaceMakerPython(InterrogateModuleDef *def) :
+  InterfaceMaker(def)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPython::write_includes
+//       Access: Public, Virtual
+//  Description: Generates the list of #include ... whatever that's
+//               required by this particular interface to the
+//               indicated output stream.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPython::
+write_includes(ostream &out) {
+  InterfaceMaker::write_includes(out);
+  out << "#undef HAVE_LONG_LONG\n"
+      << "#include <Python.h>\n\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPython::test_assert
+//       Access: Protected
+//  Description: Outputs code to check to see if an assertion has
+//               failed while the C++ code was executing, and report
+//               this failure back to Python.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPython::
+test_assert(ostream &out, int indent_level) const {
+  if (watch_asserts) {
+    out << "#ifndef NDEBUG\n";
+    indent(out, indent_level)
+      << "Notify *notify = Notify::ptr();\n";
+    indent(out, indent_level)
+      << "if (notify->has_assert_failed()) {\n";
+    indent(out, indent_level + 2)
+      << "PyErr_SetString(PyExc_AssertionError, notify->get_assert_error_message().c_str());\n";
+    indent(out, indent_level + 2)
+      << "notify->clear_assert_failed();\n";
+    indent(out, indent_level + 2)
+      << "return (PyObject *)NULL;\n";
+    indent(out, indent_level)
+      << "}\n";
+    out << "#endif\n";
+  }
+}

+ 46 - 0
dtool/src/interrogate/interfaceMakerPython.h

@@ -0,0 +1,46 @@
+// Filename: interfaceMakerPython.h
+// Created by:  drose (21Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef INTERFACEMAKERPYTHON_H
+#define INTERFACEMAKERPYTHON_H
+
+#include "dtoolbase.h"
+
+#include "interfaceMaker.h"
+
+class FunctionRemap;
+
+////////////////////////////////////////////////////////////////////
+//       Class : InterfaceMakerPython
+// Description : The base class for InteraceMakerPythonSimple and
+//               InterfaceMakerPythonObj, this includes a few
+//               functions that both have in common for formatting
+//               Python objects.
+////////////////////////////////////////////////////////////////////
+class InterfaceMakerPython : public InterfaceMaker {
+protected:
+  InterfaceMakerPython(InterrogateModuleDef *def);
+
+public:
+  virtual void write_includes(ostream &out);
+
+protected:
+  void test_assert(ostream &out, int indent_level) const;
+};
+
+#endif

+ 574 - 0
dtool/src/interrogate/interfaceMakerPythonObj.cxx

@@ -0,0 +1,574 @@
+// Filename: interfaceMakerPythonObj.cxx
+// Created by:  drose (19Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "interfaceMakerPythonObj.h"
+#include "interrogateBuilder.h"
+#include "interrogate.h"
+#include "functionRemap.h"
+#include "parameterRemapUnchanged.h"
+#include "typeManager.h"
+#include "functionWriterPtrFromPython.h"
+#include "functionWriterPtrToPython.h"
+
+#include "interrogateDatabase.h"
+#include "interrogateType.h"
+#include "interrogateFunction.h"
+#include "cppFunctionType.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMakerPythonObj::
+InterfaceMakerPythonObj(InterrogateModuleDef *def) :
+  InterfaceMakerPython(def)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMakerPythonObj::
+~InterfaceMakerPythonObj() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::write_prototypes
+//       Access: Public, Virtual
+//  Description: Generates the list of function prototypes
+//               corresponding to the functions that will be output in
+//               write_functions().
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonObj::
+write_prototypes(ostream &out) {
+  Functions::iterator fi;
+  for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
+    Function *func = (*fi);
+    write_prototype_for(out, func);
+  }
+
+  out << "\n";
+  InterfaceMakerPython::write_prototypes(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::write_functions
+//       Access: Public, Virtual
+//  Description: Generates the list of functions that are appropriate
+//               for this interface.  This function is called *before*
+//               write_prototypes(), above.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonObj::
+write_functions(ostream &out) {
+  Functions::iterator fi;
+  for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
+    Function *func = (*fi);
+    write_function_for(out, func);
+  }
+
+  InterfaceMakerPython::write_functions(out);
+
+  // Finally, generate all the make-class-wrapper functions.
+  Objects::iterator oi;
+  for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
+    Object *object = (*oi).second;
+
+    write_class_wrapper(out, object);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::write_module
+//       Access: Public, Virtual
+//  Description: Generates whatever additional code is required to
+//               support a module file.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonObj::
+write_module(ostream &out, InterrogateModuleDef *def) {
+  InterfaceMakerPython::write_module(out, def);
+
+  out << "static PyMethodDef python_obj_funcs[] = {\n";
+
+  Objects::iterator oi;
+  for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
+    Object *object = (*oi).second;
+
+    Functions::iterator fi;
+    for (fi = object->_constructors.begin(); 
+         fi != object->_constructors.end(); 
+         ++fi) {
+      Function *func = (*fi);
+      out << "  { \"" << func->_ifunc.get_name() << "\", &" << func->_name 
+          << ", METH_VARARGS },\n";
+    }
+  }  
+  out << "  { NULL, NULL }\n"
+      << "};\n\n"
+
+      << "#ifdef _WIN32\n"
+      << "extern \"C\" __declspec(dllexport) void init" << def->library_name << "();\n"
+      << "#else\n"
+      << "extern \"C\" void init" << def->library_name << "();\n"
+      << "#endif\n\n"
+    
+      << "void init" << def->library_name << "() {\n"
+      << "  Py_InitModule(\"" << def->library_name
+      << "\", python_obj_funcs);\n"
+      << "}\n\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::synthesize_this_parameter
+//       Access: Public, Virtual
+//  Description: This method should be overridden and redefined to
+//               return true for interfaces that require the implicit
+//               "this" parameter, if present, to be passed as the
+//               first parameter to any wrapper functions.
+////////////////////////////////////////////////////////////////////
+bool InterfaceMakerPythonObj::
+synthesize_this_parameter() {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::get_builder_name
+//       Access: Public, Static
+//  Description: Returns the name of the InterfaceMaker function
+//               generated to define the Python class for the
+//               indicated struct type.
+////////////////////////////////////////////////////////////////////
+string InterfaceMakerPythonObj::
+get_builder_name(CPPType *struct_type) {
+  return "get_python_class_" + 
+    InterrogateBuilder::clean_identifier(struct_type->get_local_name(&parser));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::get_wrapper_prefix
+//       Access: Protected, Virtual
+//  Description: Returns the prefix string used to generate wrapper
+//               function names.
+////////////////////////////////////////////////////////////////////
+string InterfaceMakerPythonObj::
+get_wrapper_prefix() {
+  return "wpo_";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::write_class_wrapper
+//       Access: Private
+//  Description: Writes a function that will define the Python class.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonObj::
+write_class_wrapper(ostream &out, InterfaceMaker::Object *object) {
+  CPPType *struct_type = object->_itype._cpptype;
+  if (struct_type == (CPPType *)NULL) {
+    return;
+  }
+
+  string name = get_builder_name(struct_type);
+  string python_name =
+    InterrogateBuilder::clean_identifier(struct_type->get_simple_name());
+
+  out << "/*\n"
+      << " * Generate unique Python class for "
+      << struct_type->get_local_name(&parser) << "\n"
+      << " */\n"
+      << "PyObject *\n"
+      << name << "() {\n"
+      << "  static PyObject *wrapper = (PyObject *)NULL;\n"
+      << "  static PyMethodDef methods[] = {\n";
+
+  int methods_size = 0;
+  int class_methods_size = 0;
+
+  Functions::iterator fi;
+  for (fi = object->_methods.begin(); fi != object->_methods.end(); ++fi) {
+    Function *func = (*fi);
+    if (func->_has_this) {
+      out << "  { \"" << func->_ifunc.get_name() << "\", &" << func->_name 
+          << ", METH_VARARGS },\n";
+      methods_size++;
+    }
+  }
+
+  out << "  };\n"
+      << "  static const int methods_size = " << methods_size << ";\n\n"
+      << "  static PyMethodDef class_methods[] = {\n";
+
+  for (fi = object->_methods.begin(); fi != object->_methods.end(); ++fi) {
+    Function *func = (*fi);
+    if (!func->_has_this) {
+      out << "  { \"" << func->_ifunc.get_name() << "\", &" << func->_name 
+          << ", METH_VARARGS },\n";
+      class_methods_size++;
+    }
+  }
+
+  out << "  };\n"
+      << "  static const int class_methods_size = " << class_methods_size << ";\n\n"
+      << "  if (wrapper == (PyObject *)NULL) {\n"
+      << "    int i;\n"
+      << "    PyObject *bases = PyTuple_New(0);\n"
+      << "    PyObject *dict = PyDict_New();\n"
+      << "    PyObject *name = PyString_FromString(\""
+      << python_name << "\");\n"
+      << "    wrapper = PyClass_New(bases, dict, name);\n"
+      << "    for (i = 0; i < methods_size; i++) {\n"
+      << "      PyObject *function, *method;\n"
+      << "      function = PyCFunction_New(&methods[i], (PyObject *)NULL);\n"
+      << "      method = PyMethod_New(function, (PyObject *)NULL, wrapper);\n"
+      << "      PyDict_SetItemString(dict, methods[i].ml_name, method);\n"
+      << "    }\n"
+      << "    for (i = 0; i < class_methods_size; i++) {\n"
+      << "      PyObject *function;\n"
+      << "      function = PyCFunction_New(&class_methods[i], (PyObject *)NULL);\n"
+      << "      PyDict_SetItemString(dict, class_methods[i].ml_name, function);\n"
+      << "    }\n"
+      << "  }\n"
+      << "  return wrapper;\n"
+      << "}\n\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::write_prototype_for
+//       Access: Private
+//  Description: Writes the prototype for the indicated function.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonObj::
+write_prototype_for(ostream &out, InterfaceMaker::Function *func) {
+  out << "static PyObject *"
+      << func->_name << "(PyObject *self, PyObject *args);\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::write_function_for
+//       Access: Private
+//  Description: Writes the definition for a function that will call
+//               the indicated C++ function or method.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonObj::
+write_function_for(ostream &out, InterfaceMaker::Function *func) {
+  Function::Remaps::const_iterator ri;
+  out << "/*\n"
+      << " * Python object wrapper for\n";
+  for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
+    FunctionRemap *remap = (*ri);
+    out << " * ";
+    remap->write_orig_prototype(out, 0);
+    out << "\n";
+  }
+  out << " */\n";
+
+  out << "static PyObject *"
+      << func->_name << "(PyObject *, PyObject *args) {\n";
+
+  // Now write out each instance of the overloaded function.
+  string expected_params = "Arguments must match one of:";
+
+  for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
+    FunctionRemap *remap = (*ri);
+    expected_params += "\\n  ";
+    write_function_instance(out, 2, func, remap, expected_params);
+  }
+
+  // If we get here in the generated code, none of the parameters were
+  // valid.  Generate an error exception.  (We don't rely on the error
+  // already generated by ParseTuple(), because it only reports the
+  // error for one flavor of the function, whereas we might accept
+  // multiple flavors for the different overloaded C++ function
+  // signatures.
+
+  out << "  PyErr_SetString(PyExc_TypeError, \"" << expected_params << "\");\n"
+      << "  return (PyObject *)NULL;\n";
+
+  out << "}\n\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::write_function_instance
+//       Access: Private
+//  Description: Writes out the part of a function that handles a
+//               single instance of an overloaded function.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonObj::
+write_function_instance(ostream &out, int indent_level,
+                        InterfaceMaker::Function *func,
+                        FunctionRemap *remap, string &expected_params) {
+  indent(out, indent_level) << "{\n";
+  indent(out, indent_level + 2) << "/* ";
+  remap->write_orig_prototype(out, 0);
+  out << " */\n\n";
+  
+  string format_specifiers;
+  string parameter_list;
+  vector_string pexprs;
+
+  // Make one pass through the parameter list.  We will output a
+  // one-line temporary variable definition for each parameter, while
+  // simultaneously building the ParseTuple() function call and also
+  // the parameter expression list for call_function().
+
+  expected_params += remap->_cppfunc->get_simple_name();
+  expected_params += "(";
+
+  int pn;
+  for (pn = 0; pn < (int)remap->_parameters.size(); pn++) {
+    if (pn != 0) {
+      expected_params += ", ";
+    }
+
+    indent(out, indent_level + 2);
+    CPPType *orig_type = remap->_parameters[pn]._remap->get_orig_type();
+    CPPType *type = remap->_parameters[pn]._remap->get_new_type();
+    string param_name = remap->get_parameter_name(pn);
+    
+    // This is the string to convert our local variable to the
+    // appropriate C++ type.  Normally this is just a cast.
+    string pexpr_string =
+      "(" + type->get_local_name(&parser) + ")" + param_name;
+    
+    if (remap->_parameters[pn]._remap->new_type_is_atomic_string()) {
+      if (TypeManager::is_char_pointer(orig_type)) {
+        out << "char *" << param_name;
+        format_specifiers += "s";
+        parameter_list += ", &" + param_name;
+        
+      } else {
+        out << "char *" << param_name
+            << "_str; int " << param_name << "_len";
+        format_specifiers += "s#";
+        parameter_list += ", &" + param_name
+          + "_str, &" + param_name + "_len";
+        pexpr_string = "basic_string<char>(" +
+          param_name + "_str, " +
+          param_name + "_len)";
+      }
+      expected_params += "string";
+      
+    } else if (TypeManager::is_bool(type)) {
+      out << "PyObject *" << param_name;
+      format_specifiers += "O";
+      parameter_list += ", &" + param_name;
+      pexpr_string = "(PyObject_IsTrue(" + param_name + ")!=0)";
+      expected_params += "bool";
+
+    } else if (TypeManager::is_integer(type)) {
+      out << "int " << param_name;
+      format_specifiers += "i";
+      parameter_list += ", &" + param_name;
+      expected_params += "integer";
+
+    } else if (TypeManager::is_float(type)) {
+      out << "double " << param_name;
+      format_specifiers += "d";
+      parameter_list += ", &" + param_name;
+      expected_params += "float";
+
+    } else if (TypeManager::is_char_pointer(type)) {
+      out << "char *" << param_name;
+      format_specifiers += "s";
+      parameter_list += ", &" + param_name;
+      expected_params += "string";
+
+    } else if (TypeManager::is_pointer(type)) {
+      FunctionWriterPtrFromPython *writer = get_ptr_from_python(type);
+      writer->get_pointer_type()->output_instance(out, param_name, &parser);
+      format_specifiers += "O&";
+      parameter_list += ", &" + writer->get_name() + ", &" + param_name;
+      expected_params += writer->get_type()->get_preferred_name();
+
+    } else {
+      // Ignore a parameter.
+      out << "PyObject *" << param_name;
+      format_specifiers += "O";
+      parameter_list += ", &" + param_name;
+      expected_params += "any";
+    }
+
+    if (remap->_parameters[pn]._has_name) {
+      expected_params += " " + remap->_parameters[pn]._name;
+    }
+
+    out << ";\n";
+    pexprs.push_back(pexpr_string);
+  }
+  expected_params += ")";
+
+  indent(out, indent_level + 2)
+    << "if (PyArg_ParseTuple(args, \"" << format_specifiers
+    << "\"" << parameter_list << ")) {\n";
+
+  if (track_interpreter) {
+    indent(out, indent_level + 4)
+      << "in_interpreter = 0;\n";
+  }
+
+  if (!remap->_void_return && 
+      remap->_return_type->new_type_is_atomic_string()) {
+    // Treat strings as a special case.  We don't want to format the
+    // return expression.
+    string return_expr = 
+      remap->call_function(out, indent_level + 4, false, "param0", pexprs);
+
+    CPPType *type = remap->_return_type->get_orig_type();
+    indent(out, indent_level + 4);
+    type->output_instance(out, "return_value", &parser);
+    out << " = " << return_expr << ";\n";
+
+    if (track_interpreter) {
+      indent(out, indent_level + 4)
+        << "in_interpreter = 1;\n";
+    }
+
+    return_expr = manage_return_value(out, indent_level + 4, remap, "return_value");
+    test_assert(out, indent_level + 4);
+    pack_return_value(out, indent_level + 4, remap, return_expr);
+
+  } else {
+    string return_expr = 
+      remap->call_function(out, indent_level + 4, true, "param0", pexprs);
+    if (return_expr.empty()) {
+      if (track_interpreter) {
+        indent(out, indent_level + 4)
+          << "in_interpreter = 1;\n";
+      }
+      test_assert(out, indent_level + 4);
+      indent(out, indent_level + 4)
+        << "return Py_BuildValue(\"\");\n";
+
+    } else {
+      CPPType *type = remap->_return_type->get_temporary_type();
+      indent(out, indent_level + 4);
+      type->output_instance(out, "return_value", &parser);
+      out << " = " << return_expr << ";\n";
+      if (track_interpreter) {
+        indent(out, indent_level + 4)
+          << "in_interpreter = 1;\n";
+      }
+
+      return_expr = manage_return_value(out, indent_level + 4, remap, "return_value");
+      test_assert(out, indent_level + 4);
+      pack_return_value(out, indent_level + 4, remap, remap->_return_type->temporary_to_return(return_expr));
+    }
+  }
+
+  indent(out, indent_level + 2) << "}\n";
+  indent(out, indent_level + 2)
+    << "PyErr_Clear();\n";  // Clear the error generated by ParseTuple()
+  indent(out, indent_level)
+    << "}\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::pack_return_value
+//       Access: Private
+//  Description: Outputs a command to pack the indicated expression,
+//               of the return_type type, as a Python return value.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonObj::
+pack_return_value(ostream &out, int indent_level,
+                  FunctionRemap *remap, string return_expr) {
+  CPPType *orig_type = remap->_return_type->get_orig_type();
+  CPPType *type = remap->_return_type->get_new_type();
+
+  if (remap->_return_type->new_type_is_atomic_string()) {
+    if (TypeManager::is_char_pointer(orig_type)) {
+      indent(out, indent_level)
+        << "return PyString_FromString(" << return_expr << ");\n";
+
+    } else {
+      indent(out, indent_level)
+        << "return PyString_FromStringAndSize("
+        << return_expr << ".data(), " << return_expr << ".length());\n";
+    }
+
+  } else if (TypeManager::is_integer(type)) {
+    indent(out, indent_level)
+      << "return PyInt_FromLong(" << return_expr << ");\n";
+
+  } else if (TypeManager::is_float(type)) {
+    indent(out, indent_level)
+      << "return PyFloat_FromDouble(" << return_expr << ");\n";
+
+  } else if (TypeManager::is_char_pointer(type)) {
+    indent(out, indent_level)
+      << "return PyString_FromString(" << return_expr << ");\n";
+
+  } else if (TypeManager::is_pointer(type)) {
+    bool caller_manages = remap->_return_value_needs_management;
+
+    FunctionWriterPtrToPython *writer = get_ptr_to_python(type);
+    indent(out, indent_level)
+      << "return " << writer->get_name() << "((" 
+      << writer->get_pointer_type()->get_local_name(&parser) << ")"
+      << return_expr << ", " << caller_manages << ");\n";
+
+  } else {
+    // Return None.
+    indent(out, indent_level)
+      << "return Py_BuildValue(\"\");\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::get_ptr_from_python
+//       Access: Private
+//  Description: Returns a FunctionWriter pointer suitable for
+//               converting from a Python wrapper of the indicated
+//               type to the corresponding C++ pointer.
+////////////////////////////////////////////////////////////////////
+FunctionWriterPtrFromPython *InterfaceMakerPythonObj::
+get_ptr_from_python(CPPType *type) {
+  PtrConverter::iterator ci;
+  ci = _from_python.find(type);
+  if (ci != _from_python.end()) {
+    // We've previously used this type.
+    return (FunctionWriterPtrFromPython *)(*ci).second;
+  }
+
+  FunctionWriter *writer = 
+    _function_writers.add_writer(new FunctionWriterPtrFromPython(type));
+  _from_python.insert(PtrConverter::value_type(type, writer));
+  return (FunctionWriterPtrFromPython *)writer;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonObj::get_ptr_to_python
+//       Access: Private
+//  Description: Returns a FunctionWriter pointer suitable for
+//               converting from a C++ pointer of the indicated
+//               type to the corresponding Python wrapper.
+////////////////////////////////////////////////////////////////////
+FunctionWriterPtrToPython *InterfaceMakerPythonObj::
+get_ptr_to_python(CPPType *type) {
+  PtrConverter::iterator ci;
+  ci = _to_python.find(type);
+  if (ci != _to_python.end()) {
+    // We've previously used this type.
+    return (FunctionWriterPtrToPython *)(*ci).second;
+  }
+
+  FunctionWriter *writer = 
+    _function_writers.add_writer(new FunctionWriterPtrToPython(type));
+  _to_python.insert(PtrConverter::value_type(type, writer));
+  return (FunctionWriterPtrToPython *)writer;
+}

+ 77 - 0
dtool/src/interrogate/interfaceMakerPythonObj.h

@@ -0,0 +1,77 @@
+// Filename: interfaceMakerPythonObj.h
+// Created by:  drose (19Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef INTERFACEMAKERPYTHONOBJ_H
+#define INTERFACEMAKERPYTHONOBJ_H
+
+#include "dtoolbase.h"
+
+#include "interfaceMakerPython.h"
+#include "interrogate_interface.h"
+
+#include <map>
+
+class InterrogateType;
+class InterrogateFunction;
+class FunctionRemap;
+class CPPInstance;
+class FunctionWriterPtrFromPython;
+class FunctionWriterPtrToPython;
+
+////////////////////////////////////////////////////////////////////
+//       Class : InterfaceMakerPythonObj
+// Description : An InterfaceMaker suitable for generating
+//               object-oriented Python code, that can be imported and
+//               used directly by Python.
+////////////////////////////////////////////////////////////////////
+class InterfaceMakerPythonObj : public InterfaceMakerPython {
+public:
+  InterfaceMakerPythonObj(InterrogateModuleDef *def);
+  virtual ~InterfaceMakerPythonObj();
+
+  virtual void write_prototypes(ostream &out);
+  virtual void write_functions(ostream &out);
+
+  virtual void write_module(ostream &out, InterrogateModuleDef *def);
+
+  virtual bool synthesize_this_parameter();
+
+  static string get_builder_name(CPPType *struct_type);
+
+protected:
+  virtual string get_wrapper_prefix();
+
+private:
+  void write_class_wrapper(ostream &out, Object *object);
+  void write_prototype_for(ostream &out, Function *func);
+  void write_function_for(ostream &out, Function *func);
+  void write_function_instance(ostream &out, int indent_level, Function *func,
+                               FunctionRemap *remap, string &expected_params);
+
+  void pack_return_value(ostream &out, int indent_level,
+                         FunctionRemap *remap, string return_expr);
+
+  FunctionWriterPtrFromPython *get_ptr_from_python(CPPType *type);
+  FunctionWriterPtrToPython *get_ptr_to_python(CPPType *type);
+
+  typedef map<CPPType *, FunctionWriter *> PtrConverter;
+  PtrConverter _from_python;
+  PtrConverter _to_python;
+};
+
+#endif

+ 419 - 0
dtool/src/interrogate/interfaceMakerPythonSimple.cxx

@@ -0,0 +1,419 @@
+// Filename: interfaceMakerPythonSimple.cxx
+// Created by:  drose (01Oct01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "interfaceMakerPythonSimple.h"
+#include "interrogateBuilder.h"
+#include "interrogate.h"
+#include "functionRemap.h"
+#include "parameterRemapUnchanged.h"
+#include "typeManager.h"
+
+#include "interrogateDatabase.h"
+#include "interrogateType.h"
+#include "interrogateFunction.h"
+#include "cppFunctionType.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMakerPythonSimple::
+InterfaceMakerPythonSimple(InterrogateModuleDef *def) :
+  InterfaceMakerPython(def)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMakerPythonSimple::
+~InterfaceMakerPythonSimple() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::write_prototypes
+//       Access: Public, Virtual
+//  Description: Generates the list of function prototypes
+//               corresponding to the functions that will be output in
+//               write_functions().
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonSimple::
+write_prototypes(ostream &out) {
+  Functions::iterator fi;
+  for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
+    Function *func = (*fi);
+    write_prototype_for(out, func);
+  }
+
+  out << "\n";
+  InterfaceMakerPython::write_prototypes(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::write_functions
+//       Access: Public, Virtual
+//  Description: Generates the list of functions that are appropriate
+//               for this interface.  This function is called *before*
+//               write_prototypes(), above.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonSimple::
+write_functions(ostream &out) {
+  Functions::iterator fi;
+  for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
+    Function *func = (*fi);
+    write_function_for(out, func);
+  }
+
+  InterfaceMakerPython::write_functions(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::write_module
+//       Access: Public, Virtual
+//  Description: Generates whatever additional code is required to
+//               support a module file.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonSimple::
+write_module(ostream &out, InterrogateModuleDef *def) {
+  InterfaceMakerPython::write_module(out, def);
+
+  out << "static PyMethodDef python_simple_funcs[] = {\n";
+
+  Functions::iterator fi;
+  for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
+    Function *func = (*fi);
+    Function::Remaps::const_iterator ri;
+    for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
+      FunctionRemap *remap = (*ri);
+      out << "  { \"" << remap->_unique_name << "\", &" 
+          << remap->_wrapper_name << ", METH_VARARGS },\n";
+    }
+  }  
+  out << "  { NULL, NULL }\n"
+      << "};\n\n"
+
+      << "#ifdef _WIN32\n"
+      << "extern \"C\" __declspec(dllexport) void init" << def->library_name << "();\n"
+      << "#else\n"
+      << "extern \"C\" void init" << def->library_name << "();\n"
+      << "#endif\n\n"
+    
+      << "void init" << def->library_name << "() {\n"
+      << "  Py_InitModule(\"" << def->library_name
+      << "\", python_simple_funcs);\n"
+      << "}\n\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::synthesize_this_parameter
+//       Access: Public, Virtual
+//  Description: This method should be overridden and redefined to
+//               return true for interfaces that require the implicit
+//               "this" parameter, if present, to be passed as the
+//               first parameter to any wrapper functions.
+////////////////////////////////////////////////////////////////////
+bool InterfaceMakerPythonSimple::
+synthesize_this_parameter() {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::get_wrapper_prefix
+//       Access: Protected, Virtual
+//  Description: Returns the prefix string used to generate wrapper
+//               function names.
+////////////////////////////////////////////////////////////////////
+string InterfaceMakerPythonSimple::
+get_wrapper_prefix() {
+  return "_inP";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::get_unique_prefix
+//       Access: Protected, Virtual
+//  Description: Returns the prefix string used to generate unique
+//               symbolic names, which are not necessarily C-callable
+//               function names.
+////////////////////////////////////////////////////////////////////
+string InterfaceMakerPythonSimple::
+get_unique_prefix() {
+  return "p";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::record_function_wrapper
+//       Access: Protected, Virtual
+//  Description: Associates the function wrapper with its function in
+//               the appropriate structures in the database.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonSimple::
+record_function_wrapper(InterrogateFunction &ifunc, 
+                        FunctionWrapperIndex wrapper_index) {
+  ifunc._python_wrappers.push_back(wrapper_index);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::write_prototype_for
+//       Access: Private
+//  Description: Writes the prototype for the indicated function.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonSimple::
+write_prototype_for(ostream &out, InterfaceMaker::Function *func) {
+  Function::Remaps::const_iterator ri;
+
+  for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
+    FunctionRemap *remap = (*ri);
+    if (!output_function_names) {
+      // If we're not saving the function names, don't export it from
+      // the library.
+      out << "static ";
+    } else {
+      out << "extern \"C\" ";
+    }
+    out << "PyObject *"
+        << remap->_wrapper_name << "(PyObject *self, PyObject *args);\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::write_function_for
+//       Access: Private
+//  Description: Writes the definition for a function that will call
+//               the indicated C++ function or method.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonSimple::
+write_function_for(ostream &out, InterfaceMaker::Function *func) {
+  Function::Remaps::const_iterator ri;
+
+  for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
+    FunctionRemap *remap = (*ri);
+    write_function_instance(out, func, remap);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::write_function_instance
+//       Access: Private
+//  Description: Writes out the particular function that handles a
+//               single instance of an overloaded function.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonSimple::
+write_function_instance(ostream &out, InterfaceMaker::Function *func,
+                        FunctionRemap *remap) {
+  out << "/*\n"
+      << " * Python simple wrapper for\n"
+      << " * ";
+  remap->write_orig_prototype(out, 0);
+  out << "\n"
+      << " */\n";
+
+  if (!output_function_names) {
+    // If we're not saving the function names, don't export it from
+    // the library.
+    out << "static ";
+  }
+
+  out << "PyObject *\n"
+      << remap->_wrapper_name << "(PyObject *, PyObject *args) {\n";
+    
+  //  write_spam_message(def_index, out);
+
+  string format_specifiers;
+  string parameter_list;
+  string container;
+  vector_string pexprs;
+
+  // Make one pass through the parameter list.  We will output a
+  // one-line temporary variable definition for each parameter, while
+  // simultaneously building the ParseTuple() function call and also
+  // the parameter expression list for call_function().
+
+  int pn;
+  for (pn = 0; pn < (int)remap->_parameters.size(); pn++) {
+    indent(out, 2);
+    CPPType *orig_type = remap->_parameters[pn]._remap->get_orig_type();
+    CPPType *type = remap->_parameters[pn]._remap->get_new_type();
+    string param_name = remap->get_parameter_name(pn);
+    
+    // This is the string to convert our local variable to the
+    // appropriate C++ type.  Normally this is just a cast.
+    string pexpr_string =
+      "(" + type->get_local_name(&parser) + ")" + param_name;
+    
+    if (remap->_parameters[pn]._remap->new_type_is_atomic_string()) {
+      if (TypeManager::is_char_pointer(orig_type)) {
+        out << "char *" << param_name;
+        format_specifiers += "s";
+        parameter_list += ", &" + param_name;
+        
+      } else {
+        out << "char *" << param_name
+            << "_str; int " << param_name << "_len";
+        format_specifiers += "s#";
+        parameter_list += ", &" + param_name
+          + "_str, &" + param_name + "_len";
+        pexpr_string = "basic_string<char>(" +
+          param_name + "_str, " +
+          param_name + "_len)";
+      }
+      
+    } else if (TypeManager::is_bool(type)) {
+      out << "PyObject *" << param_name;
+      format_specifiers += "O";
+      parameter_list += ", &" + param_name;
+      pexpr_string = "(PyObject_IsTrue(" + param_name + ")!=0)";
+
+    } else if (TypeManager::is_integer(type)) {
+      out << "int " << param_name;
+      format_specifiers += "i";
+      parameter_list += ", &" + param_name;
+
+    } else if (TypeManager::is_float(type)) {
+      out << "double " << param_name;
+      format_specifiers += "d";
+      parameter_list += ", &" + param_name;
+
+    } else if (TypeManager::is_char_pointer(type)) {
+      out << "char *" << param_name;
+      format_specifiers += "s";
+      parameter_list += ", &" + param_name;
+
+    } else if (TypeManager::is_pointer(type)) {
+      out << "int " << param_name;
+      format_specifiers += "i";
+      parameter_list += ", &" + param_name;
+
+    } else {
+      // Ignore a parameter.
+      out << "PyObject *" << param_name;
+      format_specifiers += "O";
+      parameter_list += ", &" + param_name;
+    }
+
+    out << ";\n";
+    if (remap->_has_this && pn == 0) {
+      // The "this" parameter gets passed in separately.
+      container = pexpr_string;
+    }
+    pexprs.push_back(pexpr_string);
+  }
+
+  out << "  if (PyArg_ParseTuple(args, \"" << format_specifiers
+      << "\"" << parameter_list << ")) {\n";
+  
+  if (track_interpreter) {
+    out << "    in_interpreter = 0;\n";
+  }
+  
+  if (!remap->_void_return && 
+      remap->_return_type->new_type_is_atomic_string()) {
+    // Treat strings as a special case.  We don't want to format the
+    // return expression.
+    string return_expr = remap->call_function(out, 4, false, container, pexprs);
+    
+    CPPType *type = remap->_return_type->get_orig_type();
+    out << "    ";
+    type->output_instance(out, "return_value", &parser);
+    out << " = " << return_expr << ";\n";
+    
+    if (track_interpreter) {
+      out << "    in_interpreter = 1;\n";
+    }
+    
+    return_expr = manage_return_value(out, 4, remap, "return_value");
+    test_assert(out, 4);
+    pack_return_value(out, 4, remap, return_expr);
+    
+  } else {
+    string return_expr = remap->call_function(out, 4, true, container, pexprs);
+    if (return_expr.empty()) {
+      if (track_interpreter) {
+        out << "    in_interpreter = 1;\n";
+      }
+      test_assert(out, 4);
+      out << "    return Py_BuildValue(\"\");\n";
+      
+    } else {
+      CPPType *type = remap->_return_type->get_temporary_type();
+      out << "    ";
+      type->output_instance(out, "return_value", &parser);
+      out << " = " << return_expr << ";\n";
+      if (track_interpreter) {
+        out << "    in_interpreter = 1;\n";
+      }
+      
+      return_expr = manage_return_value(out, 4, remap, "return_value");
+      test_assert(out, 4);
+      pack_return_value(out, 4, remap, remap->_return_type->temporary_to_return(return_expr));
+    }
+  }
+  
+  out << "  }\n";
+  
+  out << "  return (PyObject *)NULL;\n";
+  out << "}\n\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMakerPythonSimple::pack_return_value
+//       Access: Private
+//  Description: Outputs a command to pack the indicated expression,
+//               of the return_type type, as a Python return value.
+////////////////////////////////////////////////////////////////////
+void InterfaceMakerPythonSimple::
+pack_return_value(ostream &out, int indent_level,
+                  FunctionRemap *remap, string return_expr) {
+  CPPType *orig_type = remap->_return_type->get_orig_type();
+  CPPType *type = remap->_return_type->get_new_type();
+
+  if (remap->_return_type->new_type_is_atomic_string()) {
+    if (TypeManager::is_char_pointer(orig_type)) {
+      indent(out, indent_level)
+        << "return PyString_FromString(" << return_expr << ");\n";
+
+    } else {
+      indent(out, indent_level)
+        << "return PyString_FromStringAndSize("
+        << return_expr << ".data(), " << return_expr << ".length());\n";
+    }
+
+  } else if (TypeManager::is_integer(type)) {
+    indent(out, indent_level)
+      << "return PyInt_FromLong(" << return_expr << ");\n";
+
+  } else if (TypeManager::is_float(type)) {
+    indent(out, indent_level)
+      << "return PyFloat_FromDouble(" << return_expr << ");\n";
+
+  } else if (TypeManager::is_char_pointer(type)) {
+    indent(out, indent_level)
+      << "return PyString_FromString(" << return_expr << ");\n";
+
+  } else if (TypeManager::is_pointer(type)) {
+    indent(out, indent_level)
+      << "return PyInt_FromLong((int)" << return_expr << ");\n";
+
+  } else {
+    // Return None.
+    indent(out, indent_level)
+      << "return Py_BuildValue(\"\");\n";
+  }
+}

+ 71 - 0
dtool/src/interrogate/interfaceMakerPythonSimple.h

@@ -0,0 +1,71 @@
+// Filename: interfaceMakerPythonSimple.h
+// Created by:  drose (01Oct01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef INTERFACEMAKERPYTHONSIMPLE_H
+#define INTERFACEMAKERPYTHONSIMPLE_H
+
+#include "dtoolbase.h"
+
+#include "interfaceMakerPython.h"
+#include "interrogate_interface.h"
+
+class FunctionRemap;
+
+////////////////////////////////////////////////////////////////////
+//       Class : InterfaceMakerPythonSimple
+// Description : An InterfaceMaker for generating simple Python
+//               function wrappers around C++ code.  This allows the
+//               C++ code to be called by Python, but not necessarily
+//               in a user-friendly or object-oriented way.
+//
+//               You probably want to use InterfaceMakerPythonObj for
+//               a full object-oriented solution.  This InterfaceMaker
+//               is primarily useful as a stopgap for our old
+//               Python-based FFI system.
+////////////////////////////////////////////////////////////////////
+class InterfaceMakerPythonSimple : public InterfaceMakerPython {
+public:
+  InterfaceMakerPythonSimple(InterrogateModuleDef *def);
+  virtual ~InterfaceMakerPythonSimple();
+
+  virtual void write_prototypes(ostream &out);
+  virtual void write_functions(ostream &out);
+
+  virtual void write_module(ostream &out, InterrogateModuleDef *def);
+
+  virtual bool synthesize_this_parameter();
+
+protected:
+  virtual string get_wrapper_prefix();
+  virtual string get_unique_prefix();
+
+  virtual void
+  record_function_wrapper(InterrogateFunction &ifunc, 
+                          FunctionWrapperIndex wrapper_index);
+
+private:
+  void write_prototype_for(ostream &out, Function *func);
+  void write_function_for(ostream &out, Function *func);
+  void write_function_instance(ostream &out, Function *func,
+                               FunctionRemap *remap);
+
+  void pack_return_value(ostream &out, int indent_level,
+                         FunctionRemap *remap, string return_expr);
+};
+
+#endif

+ 18 - 4
dtool/src/interrogate/interrogate.cxx

@@ -46,6 +46,7 @@ bool watch_asserts = false;
 bool true_wrapper_names = false;
 bool build_c_wrappers = false;
 bool build_python_wrappers = false;
+bool build_python_obj_wrappers = false;
 bool track_interpreter = false;
 bool save_unique_names = false;
 bool no_database = false;
@@ -73,6 +74,7 @@ enum CommandOptions {
   CO_true_names,
   CO_c,
   CO_python,
+  CO_python_obj,
   CO_track_interpreter,
   CO_unique_names,
   CO_nodb,
@@ -96,6 +98,7 @@ static struct option long_options[] = {
   { "true-names", no_argument, NULL, CO_true_names },
   { "c", no_argument, NULL, CO_c },
   { "python", no_argument, NULL, CO_python },
+  { "python-obj", no_argument, NULL, CO_python_obj },
   { "track-interpreter", no_argument, NULL, CO_track_interpreter },
   { "unique-names", no_argument, NULL, CO_unique_names },
   { "nodb", no_argument, NULL, CO_nodb },
@@ -229,10 +232,16 @@ void show_help() {
     << "        The shared library will be directly loadable as a Python module\n"
     << "        (especially if the module definitions are made available either by\n"
     << "        running interrogate-module later, or by specifying -do-module on\n"
-    << "        the command line now).\n\n"
+    << "        the command line now).  However, C++ objects and methods will be\n"
+    << "        converted into an object handle and a list of independent Python\n"
+    << "        functions.\n\n"
+    << "  -python-obj\n"
+    << "        Generate Python function wrappers that convert C++ objects to true\n"
+    << "        python objects, with all methods converted to Python methods.  This\n"
+    << "        is currently experimental.\n\n"
 
-    << "  Either or both of -c and/or -python may be specified.  If both are\n"
-    << "  omitted, the default is -c.\n\n"
+    << "  Any combination of -c, -python, or -python-obj may be specified.  If all\n"
+    << "  are omitted, the default is -c.\n\n"
 
     << "  -track-interpreter\n"
     << "        Generate code within each wrapper function to adjust the global\n"
@@ -369,6 +378,10 @@ main(int argc, char *argv[]) {
       build_python_wrappers = true;
       break;
 
+    case CO_python_obj:
+      build_python_obj_wrappers = true;
+      break;
+
     case CO_track_interpreter:
       track_interpreter = true;
       break;
@@ -424,7 +437,8 @@ main(int argc, char *argv[]) {
     exit(1);
   }
 
-  if (!build_c_wrappers && !build_python_wrappers) {
+  if (!build_c_wrappers && !build_python_wrappers && 
+      !build_python_obj_wrappers) {
     build_c_wrappers = true;
   }
 

+ 2 - 1
dtool/src/interrogate/interrogate.h

@@ -40,7 +40,8 @@ extern bool watch_asserts;
 extern bool true_wrapper_names;
 extern bool build_c_wrappers;
 extern bool build_python_wrappers;
-extern bool track_python;
+extern bool build_python_obj_wrappers;
+extern bool track_interpreter;
 extern bool save_unique_names;
 extern bool no_database;
 extern bool generate_spam;

File diff suppressed because it is too large
+ 461 - 349
dtool/src/interrogate/interrogateBuilder.cxx


+ 27 - 13
dtool/src/interrogate/interrogateBuilder.h

@@ -44,6 +44,10 @@ class CPPIdentifier;
 class CPPNameComponent;
 class CPPManifest;
 class InterrogateType;
+class InterrogateFunction;
+class ClassBuilder;
+class FunctionRemap;
+class InterfaceMaker;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : InterrogateBuilder
@@ -65,6 +69,7 @@ public:
   FunctionIndex get_destructor_for(CPPType *type);
 
   string get_preferred_name(CPPType *type);
+  static string hash_string(const string &name, int shift_offset);
 
 private:
   typedef set<string> Commands;
@@ -82,7 +87,7 @@ private:
   bool in_noinclude(const string &name) const;
   bool should_include(const string &filename) const;
 
-  void remap_indices();
+  void remap_indices(vector<FunctionRemap *> &remaps);
   void scan_function(CPPFunctionGroup *fgroup);
   void scan_function(CPPInstance *function);
   void scan_struct_type(CPPStructType *type);
@@ -102,8 +107,12 @@ private:
   FunctionIndex
   get_function(CPPInstance *function, string description,
                CPPStructType *struct_type, CPPScope *scope,
-               bool global, WrapperBuilder::Type wtype,
-               const string &expression = string());
+               int flags, const string &expression = string());
+
+  /*
+  WrapperBuilder *get_wrapper_builder_c(const InterrogateFunction &ifunction);
+  WrapperBuilder *get_wrapper_builder_python(const InterrogateFunction &ifunction);
+  WrapperBuilder *get_wrapper_builder_python_obj(const InterrogateFunction &ifunction);
 
   void make_wrappers();
   FunctionWrapperIndex
@@ -112,6 +121,7 @@ private:
               string description, CPPStructType *struct_type, CPPScope *scope,
               WrapperBuilder::Type wtype, const string &expression,
               int num_default_parameters);
+  */
 
   TypeIndex get_atomic_string_type();
   TypeIndex get_type(CPPType *type, bool global);
@@ -120,7 +130,8 @@ private:
   void define_wrapped_type(InterrogateType &itype, CPPPointerType *cpptype);
   void define_wrapped_type(InterrogateType &itype, CPPConstType *cpptype);
   void define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
-                          bool forced);
+                          TypeIndex type_index, bool forced);
+  void make_class_builders(TypeIndex type_index, CPPStructType *cpptype);
   void update_method_comment(CPPInstance *function, CPPStructType *struct_type,
                              CPPScope *scope);
   void define_method(CPPFunctionGroup *fgroup, InterrogateType &itype,
@@ -131,13 +142,9 @@ private:
   void define_extension_type(InterrogateType &itype,
                              CPPExtensionType *cpptype);
 
-  void hash_function_signature(WrapperBuilder *wbuilder);
-  string hash_string(const string &name,
-                     int additional_number = 0,
-                     int shift_offset = 5);
-
   static string trim_blanks(const string &str);
 
+  /*
   class NewFunction {
   public:
     CPPInstance *_function;
@@ -151,14 +158,16 @@ private:
   };
   typedef vector<NewFunction> NewFunctions;
   NewFunctions _new_functions;
+  */
 
   typedef map<string, TypeIndex> TypesByName;
-  typedef map<string, FunctionIndex> FunctionsBySignature;
-  typedef map<string, WrapperBuilder *> WrappersByHash;
+  typedef map<string, FunctionIndex> FunctionsByName;
 
   TypesByName _types_by_name;
-  FunctionsBySignature _functions_by_signature;
-  WrappersByHash _wrappers_by_hash;
+  FunctionsByName _functions_by_name;
+
+  typedef vector<ClassBuilder *> ClassBuilders;
+  ClassBuilders _class_builders;
 
   typedef map<string, char> IncludeFiles;
   IncludeFiles _include_files;
@@ -172,6 +181,11 @@ private:
   Commands _noinclude;
 
   string _library_hash_name;
+
+  typedef map<string, WrapperBuilder *> OverloadedWrappers;
+  OverloadedWrappers _python_obj_wrappers;
+
+  friend class FunctionRemap;
 };
 
 extern InterrogateBuilder builder;

+ 5 - 5
dtool/src/interrogate/parameterRemapThis.cxx

@@ -19,10 +19,10 @@
 #include "parameterRemapThis.h"
 #include "typeManager.h"
 
-#include <cppStructType.h>
-#include <cppSimpleType.h>
-#include <cppPointerType.h>
-#include <cppConstType.h>
+#include "cppType.h"
+#include "cppSimpleType.h"
+#include "cppPointerType.h"
+#include "cppConstType.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ParameterRemapThis::Constructor
@@ -30,7 +30,7 @@
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ParameterRemapThis::
-ParameterRemapThis(CPPStructType *type, bool is_const) :
+ParameterRemapThis(CPPType *type, bool is_const) :
   ParameterRemap(TypeManager::get_void_type())
 {
   if (is_const) {

+ 2 - 2
dtool/src/interrogate/parameterRemapThis.h

@@ -23,7 +23,7 @@
 
 #include "parameterRemap.h"
 
-class CPPStructType;
+class CPPType;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : ParameterRemapThis
@@ -32,7 +32,7 @@ class CPPStructType;
 ////////////////////////////////////////////////////////////////////
 class ParameterRemapThis : public ParameterRemap {
 public:
-  ParameterRemapThis(CPPStructType *type, bool is_const);
+  ParameterRemapThis(CPPType *type, bool is_const);
 
   virtual void pass_parameter(ostream &out, const string &variable_name);
   virtual string get_return_expr(const string &expression);

+ 14 - 0
dtool/src/interrogate/typeManager.cxx

@@ -1156,6 +1156,20 @@ get_function_signature(CPPInstance *function,
   return out.str();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TypeManager::get_function_name
+//       Access: Public, Static
+//  Description: Returns a string corresponding to the given function
+//               name.  This is not necessarily unique to the
+//               particular overloaded function instance, but is
+//               common among all overloaded functions of the same
+//               name.
+////////////////////////////////////////////////////////////////////
+string TypeManager::
+get_function_name(CPPInstance *function) {
+  return function->get_local_name(&parser);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TypeManager::has_protected_destructor
 //       Access: Public, Static

+ 2 - 0
dtool/src/interrogate/typeManager.h

@@ -100,6 +100,8 @@ public:
   static string get_function_signature(CPPInstance *function,
                                        int num_default_parameters = 0);
 
+  static string get_function_name(CPPInstance *function);
+
   static bool has_protected_destructor(CPPType *type);
 };
 

+ 270 - 212
dtool/src/interrogate/wrapperBuilder.cxx

@@ -42,15 +42,16 @@
 #include <notify.h>
 
 ////////////////////////////////////////////////////////////////////
-//     Function: WrapperBuilder::Constructor
+//     Function: WrapperBuilder::FunctionDef::Constructor
 //       Access: Public
-//  Description:
+//  Description: 
 ////////////////////////////////////////////////////////////////////
-WrapperBuilder::
-WrapperBuilder() {
+WrapperBuilder::FunctionDef::
+FunctionDef() {
   _return_type = (ParameterRemap *)NULL;
   _void_return = true;
   _has_this = false;
+  _is_method = false;
   _type = T_normal;
 
   _function = (CPPInstance *)NULL;
@@ -58,32 +59,19 @@ WrapperBuilder() {
   _scope = (CPPScope *)NULL;
   _ftype = (CPPFunctionType *)NULL;
   _num_default_parameters = 0;
-  _wrapper_index = 0;
 
-  _is_valid = false;
   _return_value_needs_management = false;
   _return_value_destructor = 0;
   _manage_reference_count = false;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: WrapperBuilder::Destructor
+//     Function: WrapperBuilder::FunctionDef::Destructor
 //       Access: Public
-//  Description:
+//  Description: 
 ////////////////////////////////////////////////////////////////////
-WrapperBuilder::
-~WrapperBuilder() {
-  clear();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: WrapperBuilder::clear
-//       Access: Public
-//  Description: Empties the builder and prepares it to receive a new
-//               function.
-////////////////////////////////////////////////////////////////////
-void WrapperBuilder::
-clear() {
+WrapperBuilder::FunctionDef::
+~FunctionDef() {
   Parameters::iterator pi;
   for (pi = _parameters.begin(); pi != _parameters.end(); ++pi) {
     delete (*pi)._remap;
@@ -97,7 +85,52 @@ clear() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: WrapperBuilder::set_function
+//     Function: WrapperBuilder::FunctionDef::Copy constructor
+//       Access: Private
+//  Description: These are not designed to be copied.
+////////////////////////////////////////////////////////////////////
+WrapperBuilder::FunctionDef::
+FunctionDef(const FunctionDef &) {
+  assert(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilder::FunctionDef::Copy assignment operator
+//       Access: Private
+//  Description: These are not designed to be copied.
+////////////////////////////////////////////////////////////////////
+void WrapperBuilder::FunctionDef::
+operator = (const FunctionDef &) {
+  assert(false);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilder::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+WrapperBuilder::
+WrapperBuilder() {
+  _wrapper_index = 0;
+  _is_valid = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilder::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+WrapperBuilder::
+~WrapperBuilder() {
+  Def::iterator di;
+  for (di = _def.begin(); di != _def.end(); ++di) {
+    delete (*di);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilder::add_function
 //       Access: Public
 //  Description: Sets up the builder according to the indicated
 //               function.  The value of num_default_parameters
@@ -105,63 +138,76 @@ clear() {
 //               assign to their default values for this particular
 //               wrapper.
 //
-//               Returns true if successful, false if the function
-//               cannot be wrapped for some reason.
+//               If this is called only once, then the WrapperBuilder
+//               will generate a wrapper that only calls the
+//               particular C++ function.  Otherwise, if this is
+//               called multiple times (and the WrapperBuilder type
+//               supports this), it will generate a wrapper that can
+//               handle overloading, and will call the appropriate
+//               C++ function based on the input parameters.
+//
+//               Returns the definition index if successful, or -1 if
+//               the function cannot be wrapped for some reason.
 ////////////////////////////////////////////////////////////////////
-bool WrapperBuilder::
-set_function(CPPInstance *function, const string &description,
+int WrapperBuilder::
+add_function(CPPInstance *function, const string &description,
              CPPStructType *struct_type,
              CPPScope *scope, const string &function_signature,
              WrapperBuilder::Type type,
              const string &expression,
              int num_default_parameters) {
-  clear();
-
-  _function = function;
-  _description = description;
-  _struct_type = struct_type;
-  _scope = scope;
-  _function_signature = function_signature;
-  _expression = expression;
-  _num_default_parameters = num_default_parameters;
-  _parameters.clear();
-
-  _ftype = _function->_type->resolve_type(scope, &parser)->as_function_type();
-  assert(_ftype != (CPPFunctionType *)NULL);
-
   _is_valid = true;
-  _has_this = false;
-  _type = type;
-  _wrapper_index = 0;
-
-  if ((_ftype->_flags & CPPFunctionType::F_constructor) != 0) {
-    _type = T_constructor;
-
-  } else if ((_ftype->_flags & CPPFunctionType::F_destructor) != 0) {
-    _type = T_destructor;
-
-  } else if ((_ftype->_flags & CPPFunctionType::F_operator_typecast) != 0) {
-    _type = T_typecast_method;
+  int def_index = (int)_def.size();
+  FunctionDef *def = new FunctionDef;
+  _def.push_back(def);
+
+  def->_function = function;
+  def->_description = description;
+  def->_struct_type = struct_type;
+  def->_scope = scope;
+  def->_function_signature = function_signature;
+  def->_expression = expression;
+  def->_num_default_parameters = num_default_parameters;
+  def->_parameters.clear();
+
+  def->_ftype = def->_function->_type->resolve_type(scope, &parser)->as_function_type();
+  assert(def->_ftype != (CPPFunctionType *)NULL);
+
+  def->_has_this = false;
+  def->_is_method = false;
+  def->_type = type;
+
+  if ((def->_ftype->_flags & CPPFunctionType::F_constructor) != 0) {
+    def->_type = T_constructor;
+
+  } else if ((def->_ftype->_flags & CPPFunctionType::F_destructor) != 0) {
+    def->_type = T_destructor;
+
+  } else if ((def->_ftype->_flags & CPPFunctionType::F_operator_typecast) != 0) {
+    def->_type = T_typecast_method;
   }
 
-  if (_struct_type != (CPPStructType *)NULL &&
+  if (def->_struct_type != (CPPStructType *)NULL &&
       ((function->_storage_class & CPPInstance::SC_static) == 0) &&
-      _type != T_constructor) {
+      def->_type != T_constructor) {
 
     // If this is a method, but not a static method, and not a
-    // constructor, then we need to synthesize a "this" parameter.
-
-    Parameter param;
-    param._name = "this";
-    param._has_name = true;
-    bool is_const = (_ftype->_flags & CPPFunctionType::F_const_method) != 0;
-    param._remap = new ParameterRemapThis(_struct_type, is_const);
-    _parameters.push_back(param);
-    _has_this = true;
-
+    // constructor, then we may need to synthesize a "this" parameter.
+    def->_is_method = true;
+
+    if (synthesize_this_parameter()) {
+      Parameter param;
+      param._name = "this";
+      param._has_name = true;
+      bool is_const = (def->_ftype->_flags & CPPFunctionType::F_const_method) != 0;
+      param._remap = new ParameterRemapThis(def->_struct_type, is_const);
+      def->_parameters.push_back(param);
+      def->_has_this = true;
+    }
+      
     // Also check the name of the function.  If it's one of the
     // assignment-style operators, flag it as such.
-    string fname = _function->get_simple_name();
+    string fname = def->_function->get_simple_name();
     if (fname == "operator =" ||
         fname == "operator *=" ||
         fname == "operator /=" ||
@@ -173,14 +219,14 @@ set_function(CPPInstance *function, const string &description,
         fname == "operator ^=" ||
         fname == "operator <<=" ||
         fname == "operator >>=") {
-      _type = T_assignment_method;
+      def->_type = T_assignment_method;
     }
   }
 
   const CPPParameterList::Parameters &params =
-    _ftype->_parameters->_parameters;
+    def->_ftype->_parameters->_parameters;
   for (int i = 0; i < (int)params.size() - num_default_parameters; i++) {
-    CPPType *type = params[i]->_type->resolve_type(&parser, _scope);
+    CPPType *type = params[i]->_type->resolve_type(&parser, def->_scope);
     Parameter param;
     param._has_name = true;
     param._name = params[i]->get_simple_name();
@@ -194,115 +240,111 @@ set_function(CPPInstance *function, const string &description,
       param._name = param_name.str();
     }
 
-    param._remap = make_remap(type);
+    param._remap = make_remap(def_index, type);
     param._remap->set_default_value(params[i]->_initializer);
 
     if (!param._remap->is_valid()) {
       _is_valid = false;
     }
 
-    _parameters.push_back(param);
+    def->_parameters.push_back(param);
   }
 
-  if (_type == T_constructor) {
+  if (def->_type == T_constructor) {
     // Constructors are a special case.  These appear to return void
     // as seen by the parser, but we know they actually return a new
     // concrete instance.
 
-    if (_struct_type == (CPPStructType *)NULL) {
-      nout << "Method " << *_function << " has no struct type\n";
+    if (def->_struct_type == (CPPStructType *)NULL) {
+      nout << "Method " << *def->_function << " has no struct type\n";
       _is_valid = false;
     } else {
-      _return_type = make_remap(_struct_type);
-      _void_return = false;
+      def->_return_type = make_remap(def_index, def->_struct_type);
+      def->_void_return = false;
     }
 
-  } else if (_type == T_assignment_method) {
+  } else if (def->_type == T_assignment_method) {
     // Assignment-type methods are also a special case.  We munge
     // these to return *this, which is a semi-standard C++ convention
     // anyway.  We just enforce it.
 
-    if (_struct_type == (CPPStructType *)NULL) {
-      nout << "Method " << *_function << " has no struct type\n";
+    if (def->_struct_type == (CPPStructType *)NULL) {
+      nout << "Method " << *def->_function << " has no struct type\n";
       _is_valid = false;
     } else {
-      CPPType *ref_type = CPPType::new_type(new CPPReferenceType(_struct_type));
-      _return_type = make_remap(ref_type);
-      _void_return = false;
+      CPPType *ref_type = CPPType::new_type(new CPPReferenceType(def->_struct_type));
+      def->_return_type = make_remap(def_index, ref_type);
+      def->_void_return = false;
     }
 
   } else {
     // The normal case.
-    CPPType *rtype = _ftype->_return_type->resolve_type(&parser, _scope);
-    _return_type = make_remap(rtype);
-    _void_return = TypeManager::is_void(rtype);
+    CPPType *rtype = def->_ftype->_return_type->resolve_type(&parser, def->_scope);
+    def->_return_type = make_remap(def_index, rtype);
+    def->_void_return = TypeManager::is_void(rtype);
   }
 
-  if (!_return_type->is_valid()) {
+  if (!def->_return_type->is_valid()) {
     _is_valid = false;
   }
 
   // Do we need to manage the return value?
-  _return_value_needs_management = _return_type->return_value_needs_management();
-  _return_value_destructor = _return_type->get_return_value_destructor();
+  def->_return_value_needs_management = 
+    def->_return_type->return_value_needs_management();
+  def->_return_value_destructor = 
+    def->_return_type->get_return_value_destructor();
 
   // Should we manage a reference count?
-  CPPType *return_type = _return_type->get_new_type();
+  CPPType *return_type = def->_return_type->get_new_type();
   CPPType *return_meat_type = TypeManager::unwrap_pointer(return_type);
 
   if (manage_reference_counts &&
       TypeManager::is_reference_count_pointer(return_type) &&
       !TypeManager::has_protected_destructor(return_meat_type)) {
     // Yes!
-    _manage_reference_count = true;
-    _return_value_needs_management = true;
+    def->_manage_reference_count = true;
+    def->_return_value_needs_management = true;
 
     // This is problematic, because we might not have the class in
     // question fully defined here, particularly if the class is
     // defined in some other library.
-    _return_value_destructor = builder.get_destructor_for(return_meat_type);
+    def->_return_value_destructor = builder.get_destructor_for(return_meat_type);
+  }
+
+  if (!_is_valid) {
+    // Invalid function wrapper.  Too bad.
+    _def.pop_back();
+    delete def;
+    return -1;
   }
 
-  return _is_valid;
+  return def_index;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: WrapperBuilder::is_valid
-//       Access: Public
-//  Description: Returns true if the function was correctly mapped, or
-//               false if some parameter type is not supported and the
-//               remapped function is thus invalid.
+//     Function: WrapperBuilder::get_function_writers
+//       Access: Public, Virtual
+//  Description: Adds whatever list of FunctionWriters might be needed
+//               for this particular WrapperBuilder.  These will be
+//               generated to the output source file before
+//               write_wrapper() is called.
 ////////////////////////////////////////////////////////////////////
-bool WrapperBuilder::
-is_valid() const {
-  return _is_valid;
+void WrapperBuilder::
+get_function_writers(FunctionWriters &) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: WrapperBuilder::return_value_needs_management
-//       Access: Public
-//  Description: Returns true if the return value represents a value
-//               that was newly allocated, and hence must be
-//               explicitly deallocated later by the caller.
+//     Function: WrapperBuilder::synthesize_this_parameter
+//       Access: Public, Virtual
+//  Description: Returns true if this particular wrapper type requires
+//               an explicit "this" parameter to be added to the
+//               function parameter list when appropriate, or false if
+//               the "this" pointer will come through a different
+//               channel.
 ////////////////////////////////////////////////////////////////////
 bool WrapperBuilder::
-return_value_needs_management() const {
-  return _return_value_needs_management;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: WrapperBuilder::get_return_value_destructor
-//       Access: Public
-//  Description: If return_value_needs_management() returns true, this
-//               should return the index of the function that should
-//               be called when it is time to destruct the return
-//               value.  It will generally be the same as the
-//               destructor for the class we just returned a pointer
-//               to.
-////////////////////////////////////////////////////////////////////
-FunctionIndex WrapperBuilder::
-get_return_value_destructor() const {
-  return _return_value_destructor;
+synthesize_this_parameter() const {
+  return true;
 }
 
 
@@ -313,7 +355,10 @@ get_return_value_destructor() const {
 //               indicated type.
 ////////////////////////////////////////////////////////////////////
 ParameterRemap *WrapperBuilder::
-make_remap(CPPType *orig_type) {
+make_remap(int def_index, CPPType *orig_type) {
+  assert(def_index >= 0 && def_index < (int)_def.size());
+  const FunctionDef *def = _def[def_index];
+
   if (convert_strings) {
     if (TypeManager::is_char_pointer(orig_type)) {
       return new ParameterRemapCharStarToString(orig_type);
@@ -322,8 +367,8 @@ make_remap(CPPType *orig_type) {
     // If we're exporting a method of basic_string<char> itself, don't
     // convert basic_string<char>'s to atomic strings.
 
-    if (_struct_type == (CPPStructType *)NULL ||
-        !TypeManager::is_basic_string_char(_struct_type)) {
+    if (def->_struct_type == (CPPStructType *)NULL ||
+        !TypeManager::is_basic_string_char(def->_struct_type)) {
       if (TypeManager::is_basic_string_char(orig_type)) {
         return new ParameterRemapBasicStringToString(orig_type);
 
@@ -340,8 +385,8 @@ make_remap(CPPType *orig_type) {
 
       // Don't convert PointerTo<>'s to pointers for methods of the
       // PointerTo itself!
-      if (_struct_type == (CPPStructType *)NULL ||
-          !(pt_type->get_local_name(&parser) == _struct_type->get_local_name(&parser))) {
+      if (def->_struct_type == (CPPStructType *)NULL ||
+          !(pt_type->get_local_name(&parser) == def->_struct_type->get_local_name(&parser))) {
         return new ParameterRemapPTToPointer(orig_type);
       }
     }
@@ -383,34 +428,37 @@ make_remap(CPPType *orig_type) {
 //               new return value after processing.
 ////////////////////////////////////////////////////////////////////
 string WrapperBuilder::
-manage_return_value(ostream &out, int indent_level,
+manage_return_value(int def_index, 
+                    ostream &out, int indent_level,
                     const string &return_expr) const {
-  if (_manage_reference_count) {
+  assert(def_index >= 0 && def_index < (int)_def.size());
+  const FunctionDef *def = _def[def_index];
+  if (def->_manage_reference_count) {
     // If we're managing reference counts, and we're about to return a
     // reference countable object, then increment its count.
     if (return_expr == "return_value") {
       // If the expression is just a variable name, we can just ref it
       // directly.
-      output_ref(out, indent_level, return_expr);
+      output_ref(def_index, out, indent_level, return_expr);
       return return_expr;
 
     } else {
       // Otherwise, we should probably assign it to a temporary first,
       // so we don't invoke the function twice or something.
-      CPPType *type = _return_type->get_temporary_type();
+      CPPType *type = def->_return_type->get_temporary_type();
       indent(out, indent_level);
       type->output_instance(out, "refcount", &parser);
       out << " = " << return_expr << ";\n";
 
       indent(out, indent_level)
         << "if (" << return_expr << " != ("
-        << _return_type->get_new_type()->get_local_name(&parser) << ")0) {\n";
+        << def->_return_type->get_new_type()->get_local_name(&parser) << ")0) {\n";
       indent(out, indent_level + 2)
         << return_expr << "->ref();\n";
       indent(out, indent_level)
         << "}\n";
-      output_ref(out, indent_level, "refcount");
-      return _return_type->temporary_to_return("refcount");
+      output_ref(def_index, out, indent_level, "refcount");
+      return def->_return_type->temporary_to_return("refcount");
     }
   }
 
@@ -425,8 +473,10 @@ manage_return_value(ostream &out, int indent_level,
 //               the indicated variable name.
 ////////////////////////////////////////////////////////////////////
 void WrapperBuilder::
-output_ref(ostream &out, int indent_level, const string &varname) const {
-  if (_type == T_constructor || _type == T_typecast) {
+output_ref(int def_index, ostream &out, int indent_level, const string &varname) const {
+  assert(def_index >= 0 && def_index < (int)_def.size());
+  const FunctionDef *def = _def[def_index];
+  if (def->_type == T_constructor || def->_type == T_typecast) {
     // In either of these cases, we can safely assume the pointer will
     // never be NULL.
     indent(out, indent_level)
@@ -438,7 +488,7 @@ output_ref(ostream &out, int indent_level, const string &varname) const {
 
     indent(out, indent_level)
       << "if (" << varname << " != ("
-      << _return_type->get_new_type()->get_local_name(&parser) << ")0) {\n";
+      << def->_return_type->get_new_type()->get_local_name(&parser) << ")0) {\n";
     indent(out, indent_level + 2)
       << varname << "->ref();\n";
     indent(out, indent_level)
@@ -453,14 +503,14 @@ output_ref(ostream &out, int indent_level, const string &varname) const {
 ////////////////////////////////////////////////////////////////////
 string WrapperBuilder::
 get_parameter_name(int n) const {
-  // Just for the fun of it, we'll name the "this" parameter something
-  // different.
+  /*
   if (_has_this) {
     if (n == 0) {
       return "container";
     }
     n--;
   }
+  */
 
   ostringstream str;
   str << "param" << n;
@@ -492,57 +542,59 @@ get_parameter_expr(int n, const vector_string &pexprs) const {
 //               parameter value.
 ////////////////////////////////////////////////////////////////////
 string WrapperBuilder::
-get_call_str(const vector_string &pexprs) const {
+get_call_str(int def_index,
+             const string &container, const vector_string &pexprs) const {
+  assert(def_index >= 0 && def_index < (int)_def.size());
+  const FunctionDef *def = _def[def_index];
+
   // Build up the call to the actual function.
   ostringstream call;
 
-  int pn = 0;
-
   // Getters and setters are a special case.
-  if (_type == T_getter) {
-    if (_has_this) {
-      call << "(" << get_parameter_expr(pn, pexprs) << ")->"
-           << _expression;
+  if (def->_type == T_getter) {
+    if (!container.empty()) {
+      call << "(" << container << ")->" << def->_expression;
     } else {
-      call << _expression;
+      call << def->_expression;
     }
+    assert(def->_parameters.empty());
 
-  } else if (_type == T_setter) {
-    if (_has_this) {
-      call << "(" << get_parameter_expr(pn, pexprs) << ")->"
-           << _expression;
-      pn++;
+  } else if (def->_type == T_setter) {
+    if (!container.empty()) {
+      call << "(" << container << ")->" << def->_expression;
     } else {
-      call << _expression;
+      call << def->_expression;
     }
 
     call << " = ";
-    assert(pn + 1 == (int)_parameters.size());
-    _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
+    assert(def->_parameters.size() == 1);
+    def->_parameters[0]._remap->pass_parameter(call, get_parameter_expr(0, pexprs));
 
   } else {
-    if (_has_this) {
-      // If we have a synthesized "this" parameter, the calling
-      // convention is a bit different.
-      call << "(" << get_parameter_expr(pn, pexprs) << ")->"
-           << _function->get_local_name();
-      pn++;
-
-    } else if (_type == T_constructor) {
-      // Constructors are called differently too.
-      call << _struct_type->get_local_name(&parser);
-
+    int pn = 0;
+    if (def->_type == T_constructor) {
+      // Constructors are called differently.
+      call << def->_struct_type->get_local_name(&parser);
+
+    } else if (!container.empty()) {
+      // If we have a "this" parameter, the calling convention is also
+      // a bit different.
+      call << "(" << container << ")->" << def->_function->get_local_name();
+      if (def->_has_this) {
+        pn++;
+      }
+      
     } else {
-      call << _function->get_local_name(&parser);
+      call << def->_function->get_local_name(&parser);
     }
 
     call << "(";
-    if (pn < (int)_parameters.size()) {
-      _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
+    if (pn < (int)def->_parameters.size()) {
+      def->_parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
       pn++;
-      while (pn < (int)_parameters.size()) {
+      while (pn < (int)def->_parameters.size()) {
         call << ", ";
-        _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
+        def->_parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
         pn++;
       }
     }
@@ -567,77 +619,80 @@ get_call_str(const vector_string &pexprs) const {
 //               return nothing.
 ////////////////////////////////////////////////////////////////////
 string WrapperBuilder::
-call_function(ostream &out, int indent_level, bool convert_result,
-              const vector_string &pexprs) const {
+call_function(int def_index,
+              ostream &out, int indent_level, bool convert_result,
+              const string &container, const vector_string &pexprs) const {
+  assert(def_index >= 0 && def_index < (int)_def.size());
+  const FunctionDef *def = _def[def_index];
+
   string return_expr;
 
-  if (_type == T_destructor) {
+  if (def->_type == T_destructor) {
     // A destructor wrapper is just a wrapper around the delete operator.
-    assert(_parameters.size() == 1);
-    assert(_has_this);
-    assert(_struct_type != (CPPStructType *)NULL);
+    assert(!container.empty());
+    assert(def->_struct_type != (CPPStructType *)NULL);
 
-    if (TypeManager::is_reference_count(_struct_type)) {
+    if (TypeManager::is_reference_count(def->_struct_type)) {
       // Except for a reference-count type object, in which case the
       // destructor is a wrapper around unref_delete().
       indent(out, indent_level)
-        << "unref_delete(" << get_parameter_expr(0, pexprs) << ");\n";
+        << "unref_delete(" << container << ");\n";
     } else {
       indent(out, indent_level)
-        << "delete " << get_parameter_expr(0, pexprs) << ";\n";
+        << "delete " << container << ";\n";
     }
 
-  } else if (_type == T_typecast_method) {
+  } else if (def->_type == T_typecast_method) {
     // A typecast method can be invoked implicitly.
-    assert(_parameters.size() == 1);
     string cast_expr =
-      "(" + _return_type->get_orig_type()->get_local_name(&parser) +
-      ")(*" + get_parameter_expr(0, pexprs) + ")";
+      "(" + def->_return_type->get_orig_type()->get_local_name(&parser) +
+      ")(*" + container + ")";
 
     if (!convert_result) {
       return_expr = cast_expr;
     } else {
       string new_str =
-        _return_type->prepare_return_expr(out, indent_level, cast_expr);
-      return_expr = _return_type->get_return_expr(new_str);
+        def->_return_type->prepare_return_expr(out, indent_level, cast_expr);
+      return_expr = def->_return_type->get_return_expr(new_str);
     }
 
-  } else if (_type == T_typecast) {
+  } else if (def->_type == T_typecast) {
     // A regular typecast converts from a pointer type to another
     // pointer type.  (This is different from the typecast method,
     // above, which converts from the concrete type to some other
     // type.)
-    assert(_parameters.size() == 1);
+    assert(!container.empty());
     string cast_expr =
-      "(" + _return_type->get_orig_type()->get_local_name(&parser) +
-      ")" + get_parameter_expr(0, pexprs);
+      "(" + def->_return_type->get_orig_type()->get_local_name(&parser) +
+      ")" + container;
 
     if (!convert_result) {
       return_expr = cast_expr;
     } else {
       string new_str =
-        _return_type->prepare_return_expr(out, indent_level, cast_expr);
-      return_expr = _return_type->get_return_expr(new_str);
+        def->_return_type->prepare_return_expr(out, indent_level, cast_expr);
+      return_expr = def->_return_type->get_return_expr(new_str);
     }
 
-  } else if (_type == T_constructor) {
+  } else if (def->_type == T_constructor) {
     // A special case for constructors.
-    return_expr = "new " + get_call_str(pexprs);
+    return_expr = "new " + get_call_str(def_index, container, pexprs);
 
-  } else if (_type == T_assignment_method) {
+  } else if (def->_type == T_assignment_method) {
     // Another special case for assignment operators.
+    assert(!container.empty());
     indent(out, indent_level)
-      << get_call_str(pexprs) << ";\n";
+      << get_call_str(def_index, container, pexprs) << ";\n";
 
-    string this_expr = get_parameter_expr(0, pexprs);
+    string this_expr = container;
     string ref_expr = "*" + this_expr;
 
     if (!convert_result) {
       return_expr = ref_expr;
     } else {
       string new_str =
-        _return_type->prepare_return_expr(out, indent_level, ref_expr);
-      return_expr = _return_type->get_return_expr(new_str);
+        def->_return_type->prepare_return_expr(out, indent_level, ref_expr);
+      return_expr = def->_return_type->get_return_expr(new_str);
 
       // Now a simple special-case test.  Often, we will have converted
       // the reference-returning assignment operator to a pointer.  In
@@ -656,34 +711,34 @@ call_function(ostream &out, int indent_level, bool convert_result,
       }
     }
 
-  } else if (_void_return) {
+  } else if (def->_void_return) {
     indent(out, indent_level)
-      << get_call_str(pexprs) << ";\n";
+      << get_call_str(def_index, container, pexprs) << ";\n";
 
   } else {
-    string call = get_call_str(pexprs);
+    string call = get_call_str(def_index, container, pexprs);
 
     if (!convert_result) {
-      return_expr = get_call_str(pexprs);
+      return_expr = get_call_str(def_index, container, pexprs);
 
     } else {
-      if (_return_type->return_value_should_be_simple()) {
+      if (def->_return_type->return_value_should_be_simple()) {
         // We have to assign the result to a temporary first; this makes
         // it a bit easier on poor old VC++.
         indent(out, indent_level);
-        _return_type->get_orig_type()->output_instance(out, "result",
-                                                       &parser);
+        def->_return_type->get_orig_type()->output_instance(out, "result",
+                                                           &parser);
         out << " = " << call << ";\n";
 
         string new_str =
-          _return_type->prepare_return_expr(out, indent_level, "result");
-        return_expr = _return_type->get_return_expr(new_str);
+          def->_return_type->prepare_return_expr(out, indent_level, "result");
+        return_expr = def->_return_type->get_return_expr(new_str);
 
       } else {
         // This should be simple enough that we can return it directly.
         string new_str =
-          _return_type->prepare_return_expr(out, indent_level, call);
-        return_expr = _return_type->get_return_expr(new_str);
+          def->_return_type->prepare_return_expr(out, indent_level, call);
+        return_expr = def->_return_type->get_return_expr(new_str);
       }
     }
   }
@@ -700,13 +755,16 @@ call_function(ostream &out, int indent_level, bool convert_result,
 //               specified on the command line.
 ////////////////////////////////////////////////////////////////////
 void WrapperBuilder::
-write_spam_message(ostream &out) const {
+write_spam_message(int def_index, ostream &out) const {
+  assert(def_index >= 0 && def_index < (int)_def.size());
+  const FunctionDef *def = _def[def_index];
+
   if (generate_spam) {
     out << "#ifndef NDEBUG\n"
         << "  if (in_" << library_name << "_cat.is_spam()) {\n"
         << "    in_" << library_name << "_cat.spam()\n"
         << "      << \"";
-    write_quoted_string(out, _description);
+    write_quoted_string(out, def->_description);
     out << "\\n\";\n"
         << "  }\n"
         << "#endif\n";

+ 69 - 35
dtool/src/interrogate/wrapperBuilder.h

@@ -32,6 +32,7 @@ class CPPStructType;
 class CPPType;
 class CPPFunctionType;
 class ParameterRemap;
+class FunctionWriters;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : WrapperBuilder
@@ -41,6 +42,17 @@ class ParameterRemap;
 //               remap from the C++ function's parameter types, as
 //               well as actually generating wrapper code.
 //
+//               This can wrap just one particular function signature,
+//               or several different function signatures with the
+//               same function name (e.g. function overloading).  In
+//               the simple kinds of wrappers, like WrapperBuilderC
+//               and WrapperBuilderPython, this is only intended to
+//               wrap one function signature per wrapper, but wrappers
+//               that can implement function overloading directly
+//               (like WrapperBuilderPythonObj) will store multiple
+//               function signatures and implement all of them within
+//               the same wrapper.
+//
 //               This is an abstract class; it doesn't actually know
 //               how to choose parameter types and synthesize
 //               wrappers; see WrapperBuilderC and
@@ -62,16 +74,16 @@ public:
   WrapperBuilder();
   virtual ~WrapperBuilder();
 
-  void clear();
-  bool set_function(CPPInstance *function, const string &description,
-                    CPPStructType *struct_type, CPPScope *scope,
-                    const string &function_signature, Type type,
-                    const string &expression,
-                    int num_default_parameters);
+  int add_function(CPPInstance *function, const string &description,
+                   CPPStructType *struct_type, CPPScope *scope,
+                   const string &function_signature, Type type,
+                   const string &expression,
+                   int num_default_parameters);
+
+  virtual void get_function_writers(FunctionWriters &writers);
 
-  bool is_valid() const;
-  bool return_value_needs_management() const;
-  FunctionIndex get_return_value_destructor() const;
+  virtual void
+  write_prototype(ostream &out, const string &wrapper_name) const=0;
 
   virtual void
   write_wrapper(ostream &out, const string &wrapper_name) const=0;
@@ -80,10 +92,12 @@ public:
   get_wrapper_name(const string &library_hash_name) const=0;
 
   virtual bool supports_atomic_strings() const=0;
+  virtual bool synthesize_this_parameter() const;
 
   enum CallingConvention {
     CC_c,
     CC_python,
+    CC_python_obj,
   };
 
   virtual CallingConvention get_calling_convention() const=0;
@@ -96,45 +110,65 @@ public:
   };
 
   typedef vector<Parameter> Parameters;
-  Parameters _parameters;
-  ParameterRemap *_return_type;
-  bool _void_return;
-  bool _has_this;
-  Type _type;
-
-  CPPInstance *_function;
-  string _description;
-  CPPStructType *_struct_type;
-  CPPScope *_scope;
-  CPPFunctionType *_ftype;
-  string _function_signature;
-  string _expression;
-  int _num_default_parameters;
+
+  class FunctionDef {
+  public:
+    FunctionDef();
+    ~FunctionDef();
+  private:
+    FunctionDef(const FunctionDef &copy);
+    void operator = (const FunctionDef &copy);
+
+  public:
+    Parameters _parameters;
+    ParameterRemap *_return_type;
+    bool _void_return;
+    bool _has_this;
+    bool _is_method;
+    Type _type;
+
+    CPPInstance *_function;
+    string _description;
+    CPPStructType *_struct_type;
+    CPPScope *_scope;
+    CPPFunctionType *_ftype;
+    string _function_signature;
+    string _expression;
+    int _num_default_parameters;
+
+    bool _return_value_needs_management;
+    FunctionIndex _return_value_destructor;
+    bool _manage_reference_count;
+  };
+
+  typedef vector<FunctionDef *> Def;
+  Def _def;
+
   string _hash;
   int _wrapper_index;
+  bool _is_valid;
 
 protected:
-  virtual ParameterRemap *make_remap(CPPType *orig_type);
-  string manage_return_value(ostream &out, int indent_level,
+  virtual ParameterRemap *make_remap(int def_index, CPPType *orig_type);
+  string manage_return_value(int def_index, 
+                             ostream &out, int indent_level,
                              const string &return_expr) const;
-  void output_ref(ostream &out, int indent_level, const string &varname) const;
+  void output_ref(int def_index, ostream &out, int indent_level, const string &varname) const;
 
   string get_parameter_name(int n) const;
   string get_parameter_expr(int n, const vector_string &pexprs) const;
 
-  string get_call_str(const vector_string &pexprs = vector_string()) const;
-  string call_function(ostream &out, int indent_level,
-                       bool convert_result = true,
+  string get_call_str(int def_index,
+                      const string &container, 
+                      const vector_string &pexprs) const;
+  string call_function(int def_index, 
+                       ostream &out, int indent_level,
+                       bool convert_result, const string &container,
                        const vector_string &pexprs = vector_string()) const;
 
-  void write_spam_message(ostream &out) const;
+  void write_spam_message(int def_index, ostream &out) const;
   void write_quoted_string(ostream &out, const string &str) const;
 
-  bool _is_valid;
-  bool _return_value_needs_management;
-  FunctionIndex _return_value_destructor;
-  bool _manage_reference_count;
-
 public:
   static ostream &indent(ostream &out, int indent_level);
 };

+ 81 - 36
dtool/src/interrogate/wrapperBuilderC.cxx

@@ -40,6 +40,47 @@ WrapperBuilderC::
 WrapperBuilderC() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderC::write_prototype
+//       Access: Public, Virtual
+//  Description: Generates the prototype for the wrapper function(s).
+////////////////////////////////////////////////////////////////////
+void WrapperBuilderC::
+write_prototype(ostream &out, const string &wrapper_name) const {
+  for (int def_index = 0; def_index < (int)_def.size(); ++def_index) {
+    const FunctionDef *def = _def[def_index];
+
+    if (!output_function_names) {
+      // If we're not saving the function names, don't export it from
+      // the library.
+      out << "static ";
+    } else {
+      out << "extern \"C\" ";
+    }
+    
+    if (def->_void_return) {
+      out << "void " << wrapper_name;
+    } else {
+      def->_return_type->get_new_type()->output_instance(out, wrapper_name, &parser);
+    }
+    
+    out << "(";
+    int pn = 0;
+    if (pn < (int)def->_parameters.size()) {
+      def->_parameters[pn]._remap->get_new_type()->
+        output_instance(out, get_parameter_name(pn), &parser);
+      pn++;
+      while (pn < (int)def->_parameters.size()) {
+        out << ", ";
+        def->_parameters[pn]._remap->get_new_type()->
+          output_instance(out, get_parameter_name(pn), &parser);
+        pn++;
+      }
+    }
+    out << ");\n";
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: WrapperBuilderC::write_wrapper
 //       Access: Public, Virtual
@@ -48,47 +89,51 @@ WrapperBuilderC() {
 ////////////////////////////////////////////////////////////////////
 void WrapperBuilderC::
 write_wrapper(ostream &out, const string &wrapper_name) const {
-  out << "/*\n"
-      << " * C wrapper for\n"
-      << " * " << _description << "\n"
-      << " */\n";
-
-  if (!output_function_names) {
-    // If we're not saving the function names, don't export it from
-    // the library.
-    out << "static ";
-  }
+  for (int def_index = 0; def_index < (int)_def.size(); ++def_index) {
+    const FunctionDef *def = _def[def_index];
 
-  if (_void_return) {
-    out << "void\n";
-  } else {
-    out << _return_type->get_new_type()->get_local_name(&parser) << "\n";
-  }
-
-  out << wrapper_name << "(";
-  int pn = 0;
-  if (pn < (int)_parameters.size()) {
-    _parameters[pn]._remap->get_new_type()->
-      output_instance(out, get_parameter_name(pn), &parser);
-    pn++;
-    while (pn < (int)_parameters.size()) {
-      out << ", ";
-      _parameters[pn]._remap->get_new_type()->
+    out << "/*\n"
+        << " * C wrapper for\n"
+        << " * " << def->_description << "\n"
+        << " */\n";
+    
+    if (!output_function_names) {
+      // If we're not saving the function names, don't export it from
+      // the library.
+      out << "static ";
+    }
+    
+    if (def->_void_return) {
+      out << "void\n";
+    } else {
+      out << def->_return_type->get_new_type()->get_local_name(&parser) << "\n";
+    }
+    
+    out << wrapper_name << "(";
+    int pn = 0;
+    if (pn < (int)def->_parameters.size()) {
+      def->_parameters[pn]._remap->get_new_type()->
         output_instance(out, get_parameter_name(pn), &parser);
       pn++;
+      while (pn < (int)def->_parameters.size()) {
+        out << ", ";
+        def->_parameters[pn]._remap->get_new_type()->
+          output_instance(out, get_parameter_name(pn), &parser);
+        pn++;
+      }
     }
+    out << ") {\n";
+    
+    write_spam_message(def_index, out);
+    
+    string return_expr = call_function(def_index, out, 2, true, "param0");
+    return_expr = manage_return_value(def_index, out, 2, return_expr);
+    if (!return_expr.empty()) {
+      out << "  return " << return_expr << ";\n";
+    }
+    
+    out << "}\n\n";
   }
-  out << ") {\n";
-
-  write_spam_message(out);
-
-  string return_expr = call_function(out, 2);
-  return_expr = manage_return_value(out, 2, return_expr);
-  if (!return_expr.empty()) {
-    out << "  return " << return_expr << ";\n";
-  }
-
-  out << "}\n\n";
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 0
dtool/src/interrogate/wrapperBuilderC.h

@@ -32,6 +32,9 @@ class WrapperBuilderC : public WrapperBuilder {
 public:
   WrapperBuilderC();
 
+  virtual void
+  write_prototype(ostream &out, const string &wrapper_name) const;
+
   virtual void
   write_wrapper(ostream &out, const string &wrapper_name) const;
 

+ 148 - 116
dtool/src/interrogate/wrapperBuilderPython.cxx

@@ -43,157 +43,186 @@ WrapperBuilderPython() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: WrapperBuilderPython::write_wrapper
+//     Function: WrapperBuilderPython::write_prototype
 //       Access: Public, Virtual
-//  Description: Generates a wrapper function to the indicated output
-//               stream.
+//  Description: Generates the prototype for the wrapper function(s).
 ////////////////////////////////////////////////////////////////////
 void WrapperBuilderPython::
-write_wrapper(ostream &out, const string &wrapper_name) const {
-  out << "/*\n"
-      << " * Python wrapper for\n"
-      << " * " << _description << "\n"
-      << " */\n";
-
+write_prototype(ostream &out, const string &wrapper_name) const {
   if (!output_function_names) {
     // If we're not saving the function names, don't export it from
     // the library.
     out << "static ";
+  } else {
+    out << "extern \"C\" ";
   }
 
-  out << "PyObject *\n"
-      << wrapper_name << "(PyObject *, PyObject *args) {\n";
-
-  write_spam_message(out);
-
-  int pn;
+  out << "PyObject *"
+      << wrapper_name << "(PyObject *, PyObject *args);\n";
+}
 
-  string format_specifiers;
-  string parameter_list;
-  vector_string pexprs;
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPython::write_wrapper
+//       Access: Public, Virtual
+//  Description: Generates a wrapper function to the indicated output
+//               stream.
+////////////////////////////////////////////////////////////////////
+void WrapperBuilderPython::
+write_wrapper(ostream &out, const string &wrapper_name) const {
+  for (int def_index = 0; def_index < (int)_def.size(); ++def_index) {
+    const FunctionDef *def = _def[def_index];
+
+    out << "/*\n"
+        << " * Python simple wrapper for\n"
+        << " * " << def->_description << "\n"
+        << " */\n";
+
+    if (!output_function_names) {
+      // If we're not saving the function names, don't export it from
+      // the library.
+      out << "static ";
+    }
 
-  // Make one pass through the parameter list.  We will output a
-  // one-line temporary variable definition for each parameter, while
-  // simultaneously building the ParseTuple() function call and also
-  // the parameter expression list for call_function().
+    out << "PyObject *\n"
+        << wrapper_name << "(PyObject *, PyObject *args) {\n";
+
+    write_spam_message(def_index, out);
+
+    int pn;
+
+    string format_specifiers;
+    string parameter_list;
+    string container;
+    vector_string pexprs;
+
+    // Make one pass through the parameter list.  We will output a
+    // one-line temporary variable definition for each parameter, while
+    // simultaneously building the ParseTuple() function call and also
+    // the parameter expression list for call_function().
+    for (pn = 0; pn < (int)def->_parameters.size(); pn++) {
+      out << "  ";
+      CPPType *orig_type = def->_parameters[pn]._remap->get_orig_type();
+      CPPType *type = def->_parameters[pn]._remap->get_new_type();
+
+      // This is the string to convert our local variable to the
+      // appropriate C++ type.  Normally this is just a cast.
+      string pexpr_string =
+        "(" + type->get_local_name(&parser) + ")" + get_parameter_name(pn);
+
+      if (def->_parameters[pn]._remap->new_type_is_atomic_string()) {
+        if (TypeManager::is_char_pointer(orig_type)) {
+          out << "char *" << get_parameter_name(pn);
+          format_specifiers += "s";
+          parameter_list += ", &" + get_parameter_name(pn);
+
+        } else {
+          out << "char *" << get_parameter_name(pn)
+              << "_str; int " << get_parameter_name(pn) << "_len";
+          format_specifiers += "s#";
+          parameter_list += ", &" + get_parameter_name(pn)
+            + "_str, &" + get_parameter_name(pn) + "_len";
+          pexpr_string = "basic_string<char>(" +
+            get_parameter_name(pn) + "_str, " +
+            get_parameter_name(pn) + "_len)";
+        }
+
+      } else if (TypeManager::is_bool(type)) {
+        out << "PyObject *" << get_parameter_name(pn);
+        format_specifiers += "O";
+        parameter_list += ", &" + get_parameter_name(pn);
+        pexpr_string = "(PyObject_IsTrue(" + get_parameter_name(pn) + ")!=0)";
 
-  for (pn = 0; pn < (int)_parameters.size(); pn++) {
-    out << "  ";
-    CPPType *orig_type = _parameters[pn]._remap->get_orig_type();
-    CPPType *type = _parameters[pn]._remap->get_new_type();
+      } else if (TypeManager::is_integer(type)) {
+        out << "int " << get_parameter_name(pn);
+        format_specifiers += "i";
+        parameter_list += ", &" + get_parameter_name(pn);
 
-    // This is the string to convert our local variable to the
-    // appropriate C++ type.  Normally this is just a cast.
-    string pexpr_string =
-      "(" + type->get_local_name(&parser) + ")" + get_parameter_name(pn);
+      } else if (TypeManager::is_float(type)) {
+        out << "double " << get_parameter_name(pn);
+        format_specifiers += "d";
+        parameter_list += ", &" + get_parameter_name(pn);
 
-    if (_parameters[pn]._remap->new_type_is_atomic_string()) {
-      if (TypeManager::is_char_pointer(orig_type)) {
+      } else if (TypeManager::is_char_pointer(type)) {
         out << "char *" << get_parameter_name(pn);
         format_specifiers += "s";
         parameter_list += ", &" + get_parameter_name(pn);
 
+      } else if (TypeManager::is_pointer(type)) {
+        out << "int " << get_parameter_name(pn);
+        format_specifiers += "i";
+        parameter_list += ", &" + get_parameter_name(pn);
+
       } else {
-        out << "char *" << get_parameter_name(pn)
-            << "_str; int " << get_parameter_name(pn) << "_len";
-        format_specifiers += "s#";
-        parameter_list += ", &" + get_parameter_name(pn)
-          + "_str, &" + get_parameter_name(pn) + "_len";
-        pexpr_string = "basic_string<char>(" +
-          get_parameter_name(pn) + "_str, " +
-          get_parameter_name(pn) + "_len)";
+        // Ignore a parameter.
+        out << "PyObject *" << get_parameter_name(pn);
+        format_specifiers += "O";
+        parameter_list += ", &" + get_parameter_name(pn);
       }
 
-    } else if (TypeManager::is_bool(type)) {
-      out << "PyObject *" << get_parameter_name(pn);
-      format_specifiers += "O";
-      parameter_list += ", &" + get_parameter_name(pn);
-      pexpr_string = "(PyObject_IsTrue(" + get_parameter_name(pn) + ")!=0)";
-
-    } else if (TypeManager::is_integer(type)) {
-      out << "int " << get_parameter_name(pn);
-      format_specifiers += "i";
-      parameter_list += ", &" + get_parameter_name(pn);
-
-    } else if (TypeManager::is_float(type)) {
-      out << "double " << get_parameter_name(pn);
-      format_specifiers += "d";
-      parameter_list += ", &" + get_parameter_name(pn);
-
-    } else if (TypeManager::is_char_pointer(type)) {
-      out << "char *" << get_parameter_name(pn);
-      format_specifiers += "s";
-      parameter_list += ", &" + get_parameter_name(pn);
-
-    } else if (TypeManager::is_pointer(type)) {
-      out << "int " << get_parameter_name(pn);
-      format_specifiers += "i";
-      parameter_list += ", &" + get_parameter_name(pn);
-
-    } else {
-      // Ignore a parameter.
-      out << "PyObject *" << get_parameter_name(pn);
-      format_specifiers += "O";
-      parameter_list += ", &" + get_parameter_name(pn);
+      out << ";\n";
+      if (def->_has_this && pn == 0) {
+        // The "this" parameter gets passed in separately.
+        container = pexpr_string;
+      }
+      pexprs.push_back(pexpr_string);
     }
 
-    out << ";\n";
-    pexprs.push_back(pexpr_string);
-  }
-
-  out << "  if (PyArg_ParseTuple(args, \"" << format_specifiers
-      << "\"" << parameter_list << ")) {\n";
-
-  if (track_interpreter) {
-    out << "    in_interpreter = 0;\n";
-  }
-
-  if (_return_type->new_type_is_atomic_string()) {
-    // Treat strings as a special case.  We don't want to format the
-    // return expression.
-    string return_expr = call_function(out, 4, false, pexprs);
-
-    CPPType *type = _return_type->get_orig_type();
-    out << "    ";
-    type->output_instance(out, "return_value", &parser);
-    out << " = " << return_expr << ";\n";
+    out << "  if (PyArg_ParseTuple(args, \"" << format_specifiers
+        << "\"" << parameter_list << ")) {\n";
 
     if (track_interpreter) {
-      out << "    in_interpreter = 1;\n";
+      out << "    in_interpreter = 0;\n";
     }
 
-    return_expr = manage_return_value(out, 4, "return_value");
-    test_assert(out, 4);
-    pack_return_value(out, return_expr);
-
-  } else {
-    string return_expr = call_function(out, 4, true, pexprs);
-    if (return_expr.empty()) {
-      if (track_interpreter) {
-        out << "    in_interpreter = 1;\n";
-      }
-      test_assert(out, 4);
-      out << "    return Py_BuildValue(\"\");\n";
+    if (def->_return_type->new_type_is_atomic_string()) {
+      // Treat strings as a special case.  We don't want to format the
+      // return expression.
+      string return_expr = call_function(def_index,
+                                         out, 4, false, container, pexprs);
 
-    } else {
-      CPPType *type = _return_type->get_temporary_type();
+      CPPType *type = def->_return_type->get_orig_type();
       out << "    ";
       type->output_instance(out, "return_value", &parser);
       out << " = " << return_expr << ";\n";
+
       if (track_interpreter) {
         out << "    in_interpreter = 1;\n";
       }
 
-      return_expr = manage_return_value(out, 4, "return_value");
+      return_expr = manage_return_value(def_index, out, 4, "return_value");
       test_assert(out, 4);
-      pack_return_value(out, _return_type->temporary_to_return(return_expr));
+      pack_return_value(def_index, out, return_expr);
+
+    } else {
+      string return_expr = call_function(def_index, 
+                                         out, 4, true, container, pexprs);
+      if (return_expr.empty()) {
+        if (track_interpreter) {
+          out << "    in_interpreter = 1;\n";
+        }
+        test_assert(out, 4);
+        out << "    return Py_BuildValue(\"\");\n";
+
+      } else {
+        CPPType *type = def->_return_type->get_temporary_type();
+        out << "    ";
+        type->output_instance(out, "return_value", &parser);
+        out << " = " << return_expr << ";\n";
+        if (track_interpreter) {
+          out << "    in_interpreter = 1;\n";
+        }
+
+        return_expr = manage_return_value(def_index, out, 4, "return_value");
+        test_assert(out, 4);
+        pack_return_value(def_index, out, def->_return_type->temporary_to_return(return_expr));
+      }
     }
-  }
 
-  out << "  }\n";
+    out << "  }\n";
 
-  out << "  return (PyObject *)NULL;\n";
-  out << "}\n\n";
+    out << "  return (PyObject *)NULL;\n";
+    out << "}\n\n";
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -263,13 +292,16 @@ test_assert(ostream &out, int indent_level) const {
 //               of the return_type type, as a Python return value.
 ////////////////////////////////////////////////////////////////////
 void WrapperBuilderPython::
-pack_return_value(ostream &out, string return_expr) const {
-  CPPType *orig_type = _return_type->get_orig_type();
-  CPPType *type = _return_type->get_new_type();
+pack_return_value(int def_index, ostream &out, string return_expr) const {
+  assert(def_index >= 0 && def_index < (int)_def.size());
+  const FunctionDef *def = _def[def_index];
+
+  CPPType *orig_type = def->_return_type->get_orig_type();
+  CPPType *type = def->_return_type->get_new_type();
 
   out << "    return Py_BuildValue(";
 
-  if (_return_type->new_type_is_atomic_string()) {
+  if (def->_return_type->new_type_is_atomic_string()) {
     if (TypeManager::is_char_pointer(orig_type)) {
       out << "\"s\", " << return_expr;
 

+ 7 - 2
dtool/src/interrogate/wrapperBuilderPython.h

@@ -26,12 +26,17 @@
 ////////////////////////////////////////////////////////////////////
 //       Class : WrapperBuilderPython
 // Description : A specialization on WrapperBuilder that builds
-//               Python-style wrapper functions.
+//               simple Python wrapper functions, simple functions
+//               that call C++ methods directly given a handle and a
+//               set of parameters.
 ////////////////////////////////////////////////////////////////////
 class WrapperBuilderPython : public WrapperBuilder {
 public:
   WrapperBuilderPython();
 
+  virtual void
+  write_prototype(ostream &out, const string &wrapper_name) const;
+
   virtual void
   write_wrapper(ostream &out, const string &wrapper_name) const;
 
@@ -43,7 +48,7 @@ public:
 
 protected:
   void test_assert(ostream &out, int indent_level) const;
-  void pack_return_value(ostream &out, string return_expr) const;
+  void pack_return_value(int def_index, ostream &out, string return_expr) const;
 };
 
 #endif

+ 457 - 0
dtool/src/interrogate/wrapperBuilderPythonObj.cxx

@@ -0,0 +1,457 @@
+// Filename: wrapperBuilderPythonObj.cxx
+// Created by:  drose (11Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "wrapperBuilderPythonObj.h"
+#include "interrogate.h"
+#include "parameterRemap.h"
+#include "typeManager.h"
+#include "functionWriterPtrFromPython.h"
+#include "functionWriterPtrToPython.h"
+#include "functionWriters.h"
+
+#include <interrogateDatabase.h>
+#include <cppInstance.h>
+#include <cppFunctionType.h>
+#include <cppParameterList.h>
+#include <cppConstType.h>
+#include <cppReferenceType.h>
+#include <cppPointerType.h>
+#include <cppSimpleType.h>
+#include <cppStructType.h>
+#include <cppExpression.h>
+#include <notify.h>
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPythonObj::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+WrapperBuilderPythonObj::
+WrapperBuilderPythonObj() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPythonObj::get_function_writers
+//       Access: Public, Virtual
+//  Description: Adds whatever list of FunctionWriters might be needed
+//               for this particular WrapperBuilder.  These will be
+//               generated to the output source file before
+//               write_wrapper() is called.
+////////////////////////////////////////////////////////////////////
+void WrapperBuilderPythonObj::
+get_function_writers(FunctionWriters &writers) {
+  for (int def_index = 0; def_index < (int)_def.size(); ++def_index) {
+    const FunctionDef *def = _def[def_index];
+
+    if (def->_is_method) {
+      FunctionWriterPtrFromPython *writer = 
+        new FunctionWriterPtrFromPython(def->_struct_type);
+      writers.add_writer(writer);
+    }
+
+    int pn;
+    for (pn = 0; pn < (int)def->_parameters.size(); pn++) {
+      CPPType *type = def->_parameters[pn]._remap->get_new_type();
+
+      if (def->_parameters[pn]._remap->new_type_is_atomic_string()) {
+      } else if (TypeManager::is_bool(type)) {
+      } else if (TypeManager::is_integer(type)) {
+      } else if (TypeManager::is_float(type)) {
+      } else if (TypeManager::is_char_pointer(type)) {
+
+      } else if (TypeManager::is_pointer(type)) {
+        FunctionWriterPtrFromPython *writer = 
+          new FunctionWriterPtrFromPython(type);
+        writers.add_writer(writer);
+      }
+    }
+
+    CPPType *type = def->_return_type->get_new_type();
+    if (def->_return_type->new_type_is_atomic_string()) {
+    } else if (TypeManager::is_integer(type)) {
+    } else if (TypeManager::is_float(type)) {
+    } else if (TypeManager::is_char_pointer(type)) {
+      
+    } else if (TypeManager::is_pointer(type)) {
+      FunctionWriterPtrToPython *writer = 
+        new FunctionWriterPtrToPython(type);
+      writers.add_writer(writer);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPythonObj::write_prototype
+//       Access: Public, Virtual
+//  Description: Generates the prototype for the wrapper function(s).
+////////////////////////////////////////////////////////////////////
+void WrapperBuilderPythonObj::
+write_prototype(ostream &out, const string &wrapper_name) const {
+  if (!output_function_names) {
+    // If we're not saving the function names, don't export it from
+    // the library.
+    out << "static ";
+  } else {
+    out << "extern \"C\" ";
+  }
+
+  out << "PyObject *"
+      << wrapper_name << "(PyObject *self, PyObject *args);\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPythonObj::write_wrapper
+//       Access: Public, Virtual
+//  Description: Generates a wrapper function to the indicated output
+//               stream.
+////////////////////////////////////////////////////////////////////
+void WrapperBuilderPythonObj::
+write_wrapper(ostream &out, const string &wrapper_name) const {
+  bool any_is_method = false;
+
+  out << "/*\n"
+      << " * Python object wrapper for\n";
+
+  for (int def_index = 0; def_index < (int)_def.size(); ++def_index) {
+    const FunctionDef *def = _def[def_index];
+    out << " * " << def->_description << "\n";
+    if (def->_is_method) {
+      any_is_method = true;
+    }
+  }
+  out << " */\n";
+
+  if (!output_function_names) {
+    // If we're not saving the function names, don't export it from
+    // the library.
+    out << "static ";
+  }
+
+  if (any_is_method) {
+    out << "PyObject *\n"
+        << wrapper_name << "(PyObject *self, PyObject *args) {\n";
+  } else {
+    out << "PyObject *\n"
+        << wrapper_name << "(PyObject *, PyObject *args) {\n";
+  }
+  
+  write_spam_message(0, out);
+  string expected_params = "Arguments must match one of:";
+
+  for (int def_index = 0; def_index < (int)_def.size(); ++def_index) {
+    const FunctionDef *def = _def[def_index];
+    out << "  {\n"
+        << "    /* " << def->_description << " */\n"
+        << "\n";
+
+    string thisptr;
+    if (def->_is_method) {
+      // Declare a "thisptr" variable.
+      thisptr = "thisptr";
+      FunctionWriterPtrFromPython *writer = 
+        new FunctionWriterPtrFromPython(def->_struct_type);
+      out << "    ";
+      writer->get_pointer_type()->output_instance(out, thisptr, &parser);
+      out << ";\n"
+          << "    if (!" << writer->get_name() << "(self, &thisptr)) {\n"
+          << "      return (PyObject *)NULL;\n"
+          << "    }\n";
+      delete writer;
+    }
+
+    string format_specifiers;
+    string parameter_list;
+    vector_string pexprs;
+
+    // Make one pass through the parameter list.  We will output a
+    // one-line temporary variable definition for each parameter, while
+    // simultaneously building the ParseTuple() function call and also
+    // the parameter expression list for call_function().
+
+    expected_params += "\\n  ";
+    expected_params += _def[0]->_function->get_simple_name();
+    expected_params += "(";
+    
+    int pn;
+    for (pn = 0; pn < (int)def->_parameters.size(); pn++) {
+      if (pn != 0) {
+        expected_params += ", ";
+      }
+
+      out << "    ";
+      CPPType *orig_type = def->_parameters[pn]._remap->get_orig_type();
+      CPPType *type = def->_parameters[pn]._remap->get_new_type();
+
+      // This is the string to convert our local variable to the
+      // appropriate C++ type.  Normally this is just a cast.
+      string pexpr_string =
+        "(" + type->get_local_name(&parser) + ")" + get_parameter_name(pn);
+
+      if (def->_parameters[pn]._remap->new_type_is_atomic_string()) {
+        if (TypeManager::is_char_pointer(orig_type)) {
+          out << "char *" << get_parameter_name(pn);
+          format_specifiers += "s";
+          parameter_list += ", &" + get_parameter_name(pn);
+
+        } else {
+          out << "char *" << get_parameter_name(pn)
+              << "_str; int " << get_parameter_name(pn) << "_len";
+          format_specifiers += "s#";
+          parameter_list += ", &" + get_parameter_name(pn)
+            + "_str, &" + get_parameter_name(pn) + "_len";
+          pexpr_string = "basic_string<char>(" +
+            get_parameter_name(pn) + "_str, " +
+            get_parameter_name(pn) + "_len)";
+        }
+        expected_params += "string";
+
+      } else if (TypeManager::is_bool(type)) {
+        out << "PyObject *" << get_parameter_name(pn);
+        format_specifiers += "O";
+        parameter_list += ", &" + get_parameter_name(pn);
+        pexpr_string = "(PyObject_IsTrue(" + get_parameter_name(pn) + ")!=0)";
+        expected_params += "bool";
+
+      } else if (TypeManager::is_integer(type)) {
+        out << "int " << get_parameter_name(pn);
+        format_specifiers += "i";
+        parameter_list += ", &" + get_parameter_name(pn);
+        expected_params += "integer";
+
+      } else if (TypeManager::is_float(type)) {
+        out << "double " << get_parameter_name(pn);
+        format_specifiers += "d";
+        parameter_list += ", &" + get_parameter_name(pn);
+        expected_params += "float";
+
+      } else if (TypeManager::is_char_pointer(type)) {
+        out << "char *" << get_parameter_name(pn);
+        format_specifiers += "s";
+        parameter_list += ", &" + get_parameter_name(pn);
+        expected_params += "string";
+
+      } else if (TypeManager::is_pointer(type)) {
+        out << "int " << get_parameter_name(pn);
+        format_specifiers += "i";
+        parameter_list += ", &" + get_parameter_name(pn);
+        expected_params += "pointer";
+
+      } else {
+        // Ignore a parameter.
+        out << "PyObject *" << get_parameter_name(pn);
+        format_specifiers += "O";
+        parameter_list += ", &" + get_parameter_name(pn);
+        expected_params += "ignored";
+      }
+
+      if (def->_parameters[pn]._has_name) {
+        expected_params += " " + def->_parameters[pn]._name;
+      }
+
+      out << ";\n";
+      pexprs.push_back(pexpr_string);
+    }
+    expected_params += ")";
+
+    out << "    if (PyArg_ParseTuple(args, \"" << format_specifiers
+        << "\"" << parameter_list << ")) {\n";
+
+    if (track_interpreter) {
+      out << "      in_interpreter = 0;\n";
+    }
+
+    if (def->_return_type->new_type_is_atomic_string()) {
+      // Treat strings as a special case.  We don't want to format the
+      // return expression.
+      string return_expr = call_function(def_index, 
+                                         out, 6, false, thisptr, pexprs);
+
+      CPPType *type = def->_return_type->get_orig_type();
+      out << "      ";
+      type->output_instance(out, "return_value", &parser);
+      out << " = " << return_expr << ";\n";
+
+      if (track_interpreter) {
+        out << "      in_interpreter = 1;\n";
+      }
+
+      return_expr = manage_return_value(def_index, out, 6, "return_value");
+      test_assert(out, 6);
+      pack_return_value(def_index, out, return_expr);
+
+    } else {
+      string return_expr = call_function(def_index,
+                                         out, 6, true, thisptr, pexprs);
+      if (return_expr.empty()) {
+        if (track_interpreter) {
+          out << "      in_interpreter = 1;\n";
+        }
+        test_assert(out, 6);
+        out << "      return Py_BuildValue(\"\");\n";
+
+      } else {
+        CPPType *type = def->_return_type->get_temporary_type();
+        out << "      ";
+        type->output_instance(out, "return_value", &parser);
+        out << " = " << return_expr << ";\n";
+        if (track_interpreter) {
+          out << "      in_interpreter = 1;\n";
+        }
+
+        return_expr = manage_return_value(def_index, out, 6, "return_value");
+        test_assert(out, 6);
+        pack_return_value(def_index, out, def->_return_type->temporary_to_return(return_expr));
+      }
+    }
+
+    out << "    }\n"
+        << "    PyErr_Clear();\n"  // Clear the error generated by ParseTuple()
+        << "  }\n";
+  }
+
+  // Invalid parameters.  Generate an error exception.  (We don't rely
+  // on the error already generated by ParseTuple(), because it only
+  // reports the error for one flavor of the function, whereas we
+  // might accept multiple flavors for the different overloaded
+  // C++ function signatures.
+
+  out << "  PyErr_SetString(PyExc_TypeError, \"" << expected_params << "\");\n"
+      << "  return (PyObject *)NULL;\n";
+  out << "}\n\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPythonObj::get_wrapper_name
+//       Access: Public, Virtual
+//  Description: Returns the callable name for this wrapper function.
+////////////////////////////////////////////////////////////////////
+string WrapperBuilderPythonObj::
+get_wrapper_name(const string &library_hash_name) const {
+  return "_inM" + library_hash_name + _hash;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPythonObj::supports_atomic_strings
+//       Access: Public, Virtual
+//  Description: Returns true if this kind of wrapper can support true
+//               atomic string objects (and not have to fiddle with
+//               char *).
+////////////////////////////////////////////////////////////////////
+bool WrapperBuilderPythonObj::
+supports_atomic_strings() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPythonObj::synthesize_this_parameter
+//       Access: Public, Virtual
+//  Description: Returns true if this particular wrapper type requires
+//               an explicit "this" parameter to be added to the
+//               function parameter list when appropriate, or false if
+//               the "this" pointer will come through a different
+//               channel.
+////////////////////////////////////////////////////////////////////
+bool WrapperBuilderPythonObj::
+synthesize_this_parameter() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPythonObj::get_calling_convention
+//       Access: Public, Virtual
+//  Description: Returns an indication of what kind of function we are
+//               building.
+////////////////////////////////////////////////////////////////////
+WrapperBuilder::CallingConvention WrapperBuilderPythonObj::
+get_calling_convention() const {
+  return CC_python_obj;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPythonObj::test_assert
+//       Access: Protected
+//  Description: Outputs code to check to see if an assertion has
+//               failed while the C++ code was executing, and report
+//               this failure back to Python.
+////////////////////////////////////////////////////////////////////
+void WrapperBuilderPythonObj::
+test_assert(ostream &out, int indent_level) const {
+  if (watch_asserts) {
+    out << "#ifndef NDEBUG\n";
+    indent(out, indent_level)
+      << "Notify *notify = Notify::ptr();\n";
+    indent(out, indent_level)
+      << "if (notify->has_assert_failed()) {\n";
+    indent(out, indent_level + 2)
+      << "PyErr_SetString(PyExc_AssertionError, notify->get_assert_error_message().c_str());\n";
+    indent(out, indent_level + 2)
+      << "notify->clear_assert_failed();\n";
+    indent(out, indent_level + 2)
+      << "return (PyObject *)NULL;\n";
+    indent(out, indent_level)
+      << "}\n";
+    out << "#endif\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: WrapperBuilderPythonObj::pack_return_value
+//       Access: Protected
+//  Description: Outputs a command to pack the indicated expression,
+//               of the return_type type, as a Python return value.
+////////////////////////////////////////////////////////////////////
+void WrapperBuilderPythonObj::
+pack_return_value(int def_index, ostream &out, string return_expr) const {
+  assert(def_index >= 0 && def_index < (int)_def.size());
+  const FunctionDef *def = _def[def_index];
+
+  CPPType *orig_type = def->_return_type->get_orig_type();
+  CPPType *type = def->_return_type->get_new_type();
+
+  if (def->_return_type->new_type_is_atomic_string()) {
+    if (TypeManager::is_char_pointer(orig_type)) {
+      out << "      return PyString_FromString(" << return_expr << ");\n";
+
+    } else {
+      out << "      return PyString_FromStringAndSize("
+          << return_expr << ".data(), " << return_expr << ".length());\n";
+    }
+
+  } else if (TypeManager::is_integer(type)) {
+    out << "      return PyInt_FromLong(" 
+        << return_expr << ");\n";
+
+  } else if (TypeManager::is_float(type)) {
+    out << "      return PyFloat_FromDouble("
+        << return_expr << ");\n";
+
+  } else if (TypeManager::is_char_pointer(type)) {
+    out << "      return PyString_FromString(" << return_expr << ");\n";
+
+  } else if (TypeManager::is_pointer(type)) {
+    bool caller_manages = def->_return_value_needs_management;
+    FunctionWriterPtrToPython *writer = 
+      new FunctionWriterPtrToPython(type);
+    out << "      return " << writer->get_name() << "(" << return_expr
+        << ", " << caller_manages << ");\n";
+
+  } else {
+    // Return None.
+    out << "      return Py_BuildValue(\"\");\n";
+  }
+}

+ 56 - 0
dtool/src/interrogate/wrapperBuilderPythonObj.h

@@ -0,0 +1,56 @@
+// Filename: wrapperBuilderPythonObj.h
+// Created by:  drose (11Sep01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef WRAPPERBUILDERPYTHONOBJ_H
+#define WRAPPERBUILDERPYTHONOBJ_H
+
+#include "dtoolbase.h"
+#include "wrapperBuilder.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : WrapperBuilderPythonObj
+// Description : A specialization on WrapperBuilder that builds
+//               sophisticated Python wrapper functions that get
+//               assembled into Python methods, and make the C++
+//               objects appeart directly as Python objects.
+////////////////////////////////////////////////////////////////////
+class WrapperBuilderPythonObj : public WrapperBuilder {
+public:
+  WrapperBuilderPythonObj();
+
+  virtual void get_function_writers(FunctionWriters &writers);
+
+  virtual void
+  write_prototype(ostream &out, const string &wrapper_name) const;
+
+  virtual void
+  write_wrapper(ostream &out, const string &wrapper_name) const;
+
+  virtual string
+  get_wrapper_name(const string &library_hash_name) const;
+
+  virtual bool supports_atomic_strings() const;
+  virtual bool synthesize_this_parameter() const;
+  virtual CallingConvention get_calling_convention() const;
+
+protected:
+  void test_assert(ostream &out, int indent_level) const;
+  void pack_return_value(int def_index, ostream &out, string return_expr) const;
+};
+
+#endif

+ 1 - 0
dtool/src/interrogatedb/interrogateComponent.h

@@ -57,6 +57,7 @@ private:
   string _name;
 
   friend class InterrogateBuilder;
+  friend class FunctionRemap;
 };
 
 #include "interrogateComponent.I"

+ 0 - 17
dtool/src/interrogatedb/interrogateFunction.I

@@ -40,23 +40,6 @@ InterrogateFunction(const InterrogateFunction &copy) {
   (*this) = copy;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: InterrogateFunction::Copy Assignment Operator
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE void InterrogateFunction::
-operator = (const InterrogateFunction &copy) {
-  InterrogateComponent::operator = (copy);
-  _flags = copy._flags;
-  _scoped_name = copy._scoped_name;
-  _comment = copy._comment;
-  _prototype = copy._prototype;
-  _class = copy._class;
-  _c_wrappers = copy._c_wrappers;
-  _python_wrappers = copy._python_wrappers;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateFunction::is_global
 //       Access: Public

+ 20 - 0
dtool/src/interrogatedb/interrogateFunction.cxx

@@ -21,6 +21,26 @@
 #include "interrogate_datafile.h"
 #include "interrogateDatabase.h"
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateFunction::Copy Assignment Operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void InterrogateFunction::
+operator = (const InterrogateFunction &copy) {
+  InterrogateComponent::operator = (copy);
+  _flags = copy._flags;
+  _scoped_name = copy._scoped_name;
+  _comment = copy._comment;
+  _prototype = copy._prototype;
+  _class = copy._class;
+  _c_wrappers = copy._c_wrappers;
+  _python_wrappers = copy._python_wrappers;
+
+  _instances = copy._instances;
+  _expression = copy._expression;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateFunction::output
 //       Access: Public

+ 23 - 3
dtool/src/interrogatedb/interrogateFunction.h

@@ -19,13 +19,15 @@
 #ifndef INTERROGATEFUNCTION_H
 #define INTERROGATEFUNCTION_H
 
-#include <dtoolbase.h>
+#include "dtoolbase.h"
 
 #include "interrogateComponent.h"
 
 #include <vector>
+#include <map>
 
 class IndexRemapper;
+class CPPInstance;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : InterrogateFunction
@@ -35,7 +37,7 @@ class EXPCL_DTOOLCONFIG InterrogateFunction : public InterrogateComponent {
 public:
   INLINE InterrogateFunction(InterrogateModuleDef *def = NULL);
   INLINE InterrogateFunction(const InterrogateFunction &copy);
-  INLINE void operator = (const InterrogateFunction &copy);
+  void operator = (const InterrogateFunction &copy);
 
   INLINE bool is_global() const;
   INLINE bool is_virtual() const;
@@ -66,7 +68,10 @@ private:
   enum Flags {
     F_global          = 0x0001,
     F_virtual         = 0x0002,
-    F_method          = 0x0004
+    F_method          = 0x0004,
+    F_typecast        = 0x0008,
+    F_getter          = 0x0010,
+    F_setter          = 0x0020,
   };
 
   int _flags;
@@ -78,7 +83,22 @@ private:
   typedef vector<FunctionWrapperIndex> Wrappers;
   Wrappers _c_wrappers;
   Wrappers _python_wrappers;
+
+public:
+  // The rest of the members in this class aren't part of the public
+  // interface to interrogate, but are used internally as the
+  // interrogate database is built.  They are valid only during the
+  // session of interrogate that generates the database, and will not
+  // be filled in when the database is reloaded from disk.
+
+  typedef map<string, CPPInstance *> Instances;
+  Instances _instances;
+  string _expression;
+
   friend class InterrogateBuilder;
+  friend class InterfaceMakerC;
+  friend class InterfaceMakerPythonSimple;
+  friend class FunctionRemap;
 };
 
 INLINE ostream &operator << (ostream &out, const InterrogateFunction &function);

+ 2 - 1
dtool/src/interrogatedb/interrogateFunctionWrapper.h

@@ -29,7 +29,7 @@ class IndexRemapper;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : InterrogateFunctionWrapper
-// Description : An internal representation of a function.
+// Description : An internal representation of a callable function.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_DTOOLCONFIG InterrogateFunctionWrapper : public InterrogateComponent {
 public:
@@ -96,6 +96,7 @@ private:
   Parameters _parameters;
 
   friend class InterrogateBuilder;
+  friend class FunctionRemap;
 };
 
 INLINE ostream &operator << (ostream &out, const InterrogateFunctionWrapper &wrapper);

+ 3 - 0
dtool/src/interrogatedb/interrogateType.I

@@ -31,6 +31,9 @@ InterrogateType(InterrogateModuleDef *def) :
   _atomic_token = AT_not_atomic;
   _wrapped_type = 0;
   _destructor = 0;
+
+  _cpptype = (CPPType *)NULL;
+  _cppscope = (CPPScope *)NULL;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 0
dtool/src/interrogatedb/interrogateType.cxx

@@ -93,6 +93,9 @@ operator = (const InterrogateType &copy) {
   _derivations = copy._derivations;
   _enum_values = copy._enum_values;
   _nested_types = copy._nested_types;
+
+  _cpptype = copy._cpptype;
+  _cppscope = copy._cppscope;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 11 - 0
dtool/src/interrogatedb/interrogateType.h

@@ -26,6 +26,8 @@
 #include <vector>
 
 class IndexRemapper;
+class CPPType;
+class CPPScope;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : InterrogateType
@@ -196,6 +198,15 @@ private:
 
   static string _empty_string;
 
+public:
+  // The rest of the members in this class aren't part of the public
+  // interface to interrogate, but are used internally as the
+  // interrogate database is built.  They are valid only during the
+  // session of interrogate that generates the database, and will not
+  // be filled in when the database is reloaded from disk.
+  CPPType *_cpptype;
+  CPPScope *_cppscope;
+
   friend class InterrogateBuilder;
 };
 

+ 4 - 4
dtool/src/interrogatedb/interrogate_interface.h

@@ -206,12 +206,12 @@ EXPCL_DTOOLCONFIG const char *interrogate_function_scoped_name(FunctionIndex fun
 
 // This returns the C++ comment written for the function, either in
 // the header file or in the .C file, or both.
-EXPCL_DTOOLCONFIG bool interrogate_function_has_comment(TypeIndex type);
-EXPCL_DTOOLCONFIG const char *interrogate_function_comment(TypeIndex type);
+EXPCL_DTOOLCONFIG bool interrogate_function_has_comment(FunctionIndex function);
+EXPCL_DTOOLCONFIG const char *interrogate_function_comment(FunctionIndex function);
 
 // This defines the function prototype as it appears in the C++
 // source, useful primarily for documentation purposes.
-EXPCL_DTOOLCONFIG const char *interrogate_function_prototype(TypeIndex type);
+EXPCL_DTOOLCONFIG const char *interrogate_function_prototype(FunctionIndex function);
 
 // This can be used to determine the class that the function is a
 // method for, if the function is a class method.
@@ -331,7 +331,7 @@ EXPCL_DTOOLCONFIG const char *interrogate_wrapper_unique_name(FunctionWrapperInd
 // thus is only available if the option -unique-names was given to
 // interrogate.
 
-// Thus function may be called without forcing a load of the complete
+// This function may be called without forcing a load of the complete
 // interrogate database.
 EXPCL_DTOOLCONFIG FunctionWrapperIndex interrogate_get_wrapper_by_unique_name(const char *unique_name);
 

+ 24 - 0
dtool/src/pystub/pystub.cxx

@@ -21,6 +21,10 @@
 extern "C" {
   EXPCL_DTOOLCONFIG int PyArg_ParseTuple(...);
   EXPCL_DTOOLCONFIG int Py_BuildValue(...);
+  EXPCL_DTOOLCONFIG int PyInt_FromLong(...);
+  EXPCL_DTOOLCONFIG int PyFloat_FromDouble(...);
+  EXPCL_DTOOLCONFIG int PyString_FromString(...);
+  EXPCL_DTOOLCONFIG int PyString_FromStringAndSize(...);
   EXPCL_DTOOLCONFIG int Py_InitModule4(...);
   EXPCL_DTOOLCONFIG int PyObject_IsTrue(...);
   EXPCL_DTOOLCONFIG int PyErr_SetString(...);
@@ -37,6 +41,26 @@ Py_BuildValue(...) {
   return 0;
 }
 
+int
+PyInt_FromLong(...) {
+  return 0;
+}
+
+int
+PyFloat_FromDouble(...) {
+  return 0;
+}
+
+int
+PyString_FromStringAndSize(...) {
+  return 0;
+}
+
+int
+PyString_FromString(...) {
+  return 0;
+}
+
 int
 Py_InitModule4(...) {
   return 0;

Some files were not shown because too many files changed in this diff