浏览代码

Merge branch 'interrogate-overhaul'

Conflicts:
	panda/src/gobj/texture.h
	panda/src/pnmimage/pnmImage.h
rdb 10 年之前
父节点
当前提交
0570d9536e
共有 100 个文件被更改,包括 3921 次插入1601 次删除
  1. 72 50
      dtool/src/cppparser/cppBison.yxx
  2. 25 4
      dtool/src/cppparser/cppDeclaration.cxx
  3. 6 3
      dtool/src/cppparser/cppDeclaration.h
  4. 100 12
      dtool/src/cppparser/cppEnumType.cxx
  5. 6 0
      dtool/src/cppparser/cppEnumType.h
  6. 132 3
      dtool/src/cppparser/cppExpression.cxx
  7. 2 0
      dtool/src/cppparser/cppExpression.h
  8. 24 1
      dtool/src/cppparser/cppExtensionType.cxx
  9. 6 1
      dtool/src/cppparser/cppExtensionType.h
  10. 42 2
      dtool/src/cppparser/cppIdentifier.cxx
  11. 5 1
      dtool/src/cppparser/cppIdentifier.h
  12. 1 1
      dtool/src/cppparser/cppInstance.cxx
  13. 2 2
      dtool/src/cppparser/cppManifest.cxx
  14. 24 10
      dtool/src/cppparser/cppPreprocessor.cxx
  15. 1 0
      dtool/src/cppparser/cppPreprocessor.h
  16. 145 65
      dtool/src/cppparser/cppScope.cxx
  17. 7 5
      dtool/src/cppparser/cppScope.h
  18. 12 4
      dtool/src/cppparser/cppSimpleType.cxx
  19. 4 2
      dtool/src/cppparser/cppSimpleType.h
  20. 10 11
      dtool/src/cppparser/cppStructType.cxx
  21. 1 0
      dtool/src/cppparser/cppTemplateParameterList.cxx
  22. 5 4
      dtool/src/cppparser/cppTemplateScope.cxx
  23. 2 1
      dtool/src/cppparser/cppTemplateScope.h
  24. 1 1
      dtool/src/cppparser/cppType.cxx
  25. 2 2
      dtool/src/cppparser/cppType.h
  26. 13 1
      dtool/src/cppparser/cppTypeProxy.cxx
  27. 1 1
      dtool/src/cppparser/cppTypeProxy.h
  28. 0 91
      dtool/src/cppparser/cppTypedef.cxx
  29. 0 42
      dtool/src/cppparser/cppTypedef.h
  30. 388 0
      dtool/src/cppparser/cppTypedefType.cxx
  31. 74 0
      dtool/src/cppparser/cppTypedefType.h
  32. 1 6
      dtool/src/cppparser/p3cppParser_composite1.cxx
  33. 9 1
      dtool/src/dtoolbase/atomicAdjust.h
  34. 4 25
      dtool/src/dtoolbase/typeHandle.cxx
  35. 1 10
      dtool/src/dtoolbase/typeHandle.h
  36. 5 0
      dtool/src/dtoolutil/Sources.pp
  37. 11 0
      dtool/src/dtoolutil/filename.I
  38. 1 61
      dtool/src/dtoolutil/filename.cxx
  39. 6 4
      dtool/src/dtoolutil/filename.h
  40. 7 39
      dtool/src/dtoolutil/globPattern.cxx
  41. 2 2
      dtool/src/dtoolutil/globPattern.h
  42. 0 0
      dtool/src/dtoolutil/lineStream.I
  43. 0 0
      dtool/src/dtoolutil/lineStream.cxx
  44. 2 2
      dtool/src/dtoolutil/lineStream.h
  45. 0 0
      dtool/src/dtoolutil/lineStreamBuf.I
  46. 0 0
      dtool/src/dtoolutil/lineStreamBuf.cxx
  47. 2 2
      dtool/src/dtoolutil/lineStreamBuf.h
  48. 2 0
      dtool/src/dtoolutil/p3dtoolutil_composite1.cxx
  49. 130 21
      dtool/src/interrogate/functionRemap.cxx
  50. 22 15
      dtool/src/interrogate/functionRemap.h
  51. 67 56
      dtool/src/interrogate/interfaceMaker.cxx
  52. 1 0
      dtool/src/interrogate/interfaceMaker.h
  53. 371 241
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  54. 90 41
      dtool/src/interrogate/interfaceMakerPythonNative.h
  55. 1 0
      dtool/src/interrogate/interrogate.cxx
  56. 1 1
      dtool/src/interrogate/interrogate.h
  57. 253 77
      dtool/src/interrogate/interrogateBuilder.cxx
  58. 5 0
      dtool/src/interrogate/interrogateBuilder.h
  59. 8 1
      dtool/src/interrogate/parameterRemapConcreteToPointer.cxx
  60. 10 1
      dtool/src/interrogate/parameterRemapReferenceToPointer.cxx
  61. 9 9
      dtool/src/interrogate/parse_file.cxx
  62. 500 28
      dtool/src/interrogate/typeManager.cxx
  63. 13 2
      dtool/src/interrogate/typeManager.h
  64. 64 16
      dtool/src/interrogatedb/dtool_super_base.cxx
  65. 30 0
      dtool/src/interrogatedb/interrogateType.I
  66. 11 0
      dtool/src/interrogatedb/interrogateType.cxx
  67. 7 0
      dtool/src/interrogatedb/interrogateType.h
  68. 6 0
      dtool/src/interrogatedb/interrogate_interface.cxx
  69. 1 0
      dtool/src/interrogatedb/interrogate_interface.h
  70. 259 232
      dtool/src/interrogatedb/py_panda.cxx
  71. 200 178
      dtool/src/interrogatedb/py_panda.h
  72. 19 2
      dtool/src/parser-inc/Python.h
  73. 7 6
      dtool/src/parser-inc/cg.h
  74. 7 0
      dtool/src/parser-inc/iostream
  75. 1 1
      dtool/src/parser-inc/ssl.h
  76. 4 0
      dtool/src/parser-inc/stdtypedefs.h
  77. 3 0
      dtool/src/parser-inc/string
  78. 3 3
      dtool/src/parser-inc/windows.h
  79. 2 10
      dtool/src/parser-inc/winsock2.h
  80. 3 51
      dtool/src/prc/notify.cxx
  81. 47 0
      dtool/src/prc/pnotify.I
  82. 3 3
      dtool/src/prc/pnotify.h
  83. 10 0
      dtool/src/pystub/pystub.cxx
  84. 1 1
      makepanda/makepanda.py
  85. 5 2
      makepanda/makepandacore.py
  86. 110 3
      panda/src/display/graphicsWindowInputDevice.I
  87. 16 17
      panda/src/display/graphicsWindowInputDevice.cxx
  88. 20 10
      panda/src/display/graphicsWindowInputDevice.h
  89. 2 2
      panda/src/distort/nonlinearImager.cxx
  90. 1 0
      panda/src/egg/eggNurbsSurface.h
  91. 39 0
      panda/src/event/pythonTask.I
  92. 101 79
      panda/src/event/pythonTask.cxx
  93. 43 4
      panda/src/event/pythonTask.h
  94. 69 0
      panda/src/express/filename_ext.cxx
  95. 41 0
      panda/src/express/filename_ext.h
  96. 45 0
      panda/src/express/globPattern_ext.cxx
  97. 40 0
      panda/src/express/globPattern_ext.h
  98. 19 15
      panda/src/express/multifile.h
  99. 3 0
      panda/src/express/p3express_ext_composite.cxx
  100. 32 1
      panda/src/express/pointerTo.I

+ 72 - 50
dtool/src/cppparser/cppBison.yxx

@@ -21,7 +21,7 @@
 #include "cppClassTemplateParameter.h"
 #include "cppTemplateParameterList.h"
 #include "cppInstanceIdentifier.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppTypeDeclaration.h"
 #include "cppVisibility.h"
 #include "cppIdentifier.h"
@@ -241,7 +241,8 @@ pop_struct() {
 %token KW_BOOL
 %token KW_CATCH
 %token KW_CHAR
-%token KW_WCHAR_T
+%token KW_CHAR16_T
+%token KW_CHAR32_T
 %token KW_CLASS
 %token KW_CONST
 %token KW_DELETE
@@ -294,6 +295,7 @@ pop_struct() {
 %token KW_VIRTUAL
 %token KW_VOID
 %token KW_VOLATILE
+%token KW_WCHAR_T
 %token KW_WHILE
 
 /* These special tokens are used to set the starting state of the
@@ -325,8 +327,7 @@ pop_struct() {
 %type <u.type> full_type
 %type <u.struct_type> anonymous_struct
 %type <u.struct_type> named_struct
-%type <u.enum_type> anonymous_enum
-%type <u.enum_type> named_enum
+%type <u.enum_type> enum
 %type <u.extension_enum> enum_keyword
 %type <u.extension_enum> struct_keyword
 %type <u.simple_type> simple_type
@@ -334,6 +335,7 @@ pop_struct() {
 %type <u.simple_type> simple_float_type
 %type <u.simple_type> simple_void_type
 %type <u.type> class_derivation_name
+%type <u.type> enum_element_type
 /*%type <u.type> typedefname*/
 %type <u.identifier> name
 %type <str> string
@@ -353,7 +355,7 @@ pop_struct() {
 
 /* Precedence rules. */
 
-%left IDENTIFIER TYPENAME_IDENTIFIER TYPEDEFNAME KW_ENUM ELLIPSIS KW_OPERATOR KW_TYPENAME KW_INT KW_SHORT KW_UNSIGNED KW_SIGNED KW_LONG KW_FLOAT KW_DOUBLE KW_CHAR KW_WCHAR_T KW_BOOL
+%left IDENTIFIER TYPENAME_IDENTIFIER TYPEDEFNAME KW_ENUM ELLIPSIS KW_OPERATOR KW_TYPENAME KW_INT KW_SHORT KW_UNSIGNED KW_SIGNED KW_LONG KW_FLOAT KW_DOUBLE KW_CHAR KW_WCHAR_T KW_CHAR16_T KW_CHAR32_T KW_BOOL
 
 %left '{' ',' ';'
 
@@ -717,7 +719,8 @@ typedef_declaration:
     if (inst != (CPPInstance *)NULL) {
       inst->_storage_class |= (current_storage_class | $1);
       current_scope->add_declaration(inst, global_scope, current_lexer, @2);
-      current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @2);
+      CPPTypedefType *typedef_type = new CPPTypedefType(inst->_type, inst->_ident, current_scope);
+      current_scope->add_declaration(typedef_type, global_scope, current_lexer, @2);
     }
   }
 }
@@ -726,19 +729,15 @@ typedef_declaration:
 typedef_instance_identifiers:
         instance_identifier maybe_initialize_or_function_body
 {
-  CPPInstance *inst = new CPPInstance(current_type, $1,
-                                      current_storage_class,
-                                      @1.file);
-  inst->set_initializer($2);
-  current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
+  CPPType *target_type = current_type;
+  CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file);
+  current_scope->add_declaration(typedef_type, global_scope, current_lexer, @1);
 }
         | instance_identifier maybe_initialize ',' typedef_instance_identifiers
 {
-  CPPInstance *inst = new CPPInstance(current_type, $1,
-                                      current_storage_class,
-                                      @1.file);
-  inst->set_initializer($2);
-  current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
+  CPPType *target_type = current_type;
+  CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file);
+  current_scope->add_declaration(typedef_type, global_scope, current_lexer, @1);
 }
         ;
 
@@ -746,20 +745,16 @@ typedef_const_instance_identifiers:
         instance_identifier maybe_initialize_or_function_body
 {
   $1->add_modifier(IIT_const);
-  CPPInstance *inst = new CPPInstance(current_type, $1,
-                                      current_storage_class,
-                                      @1.file);
-  inst->set_initializer($2);
-  current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
+  CPPType *target_type = current_type;
+  CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file);
+  current_scope->add_declaration(typedef_type, global_scope, current_lexer, @1);
 }
         | instance_identifier maybe_initialize ',' typedef_const_instance_identifiers
 {
   $1->add_modifier(IIT_const);
-  CPPInstance *inst = new CPPInstance(current_type, $1,
-                                      current_storage_class,
-                                      @1.file);
-  inst->set_initializer($2);
-  current_scope->add_declaration(new CPPTypedef(inst, current_scope == global_scope), global_scope, current_lexer, @1);
+  CPPType *target_type = current_type;
+  CPPTypedefType *typedef_type = new CPPTypedefType(target_type, $1, current_scope, @1.file);
+  current_scope->add_declaration(typedef_type, global_scope, current_lexer, @1);
 }
         ;
 
@@ -1585,11 +1580,7 @@ type:
 {
   $$ = CPPType::new_type($1);
 }
-        | anonymous_enum
-{
-  $$ = CPPType::new_type($1);
-}
-        | named_enum
+        | enum
 {
   $$ = CPPType::new_type($1);
 }
@@ -1609,7 +1600,7 @@ type:
     $$ = et;
   }
 }
-        | enum_keyword name
+        | enum_keyword name ':' enum_element_type
 {
   CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
   if (type != NULL) {
@@ -1649,11 +1640,7 @@ type_decl:
 {
   $$ = new CPPTypeDeclaration(CPPType::new_type($1));
 }
-        | anonymous_enum
-{
-  $$ = new CPPTypeDeclaration(CPPType::new_type($1));
-}
-        | named_enum
+        | enum
 {
   $$ = new CPPTypeDeclaration(CPPType::new_type($1));
 }
@@ -1673,7 +1660,7 @@ type_decl:
     $$ = et;
   }
 }
-        | enum_keyword name
+        | enum_keyword name ':' enum_element_type
 {
   CPPType *type = $2->find_type(current_scope, global_scope, false, current_lexer);
   if (type != NULL) {
@@ -1858,27 +1845,41 @@ base_specification:
 }
         ;
 
-anonymous_enum:
-        enum_keyword '{'
-{
-  current_enum = new CPPEnumType(NULL, current_scope, @1.file);
-}
-        enum_body '}'
+enum:
+        enum_decl '{' enum_body '}'
 {
   $$ = current_enum;
   current_enum = NULL;
 }
         ;
 
-named_enum:
-        enum_keyword name '{'
+enum_decl:
+        enum_keyword name ':' enum_element_type
+{
+  current_enum = new CPPEnumType($2, $4, current_scope, @1.file);
+}
+        | enum_keyword name
 {
   current_enum = new CPPEnumType($2, current_scope, @1.file);
 }
-        enum_body '}'
+        | enum_keyword ':' enum_element_type
 {
-  $$ = current_enum;
-  current_enum = NULL;
+  current_enum = new CPPEnumType(NULL, $3, current_scope, @1.file);
+}
+        | enum_keyword
+{
+  current_enum = new CPPEnumType(NULL, current_scope, @1.file);
+}
+        ;
+
+enum_element_type:
+        simple_int_type
+{
+  $$ = CPPType::new_type($1);
+}
+        | TYPENAME_IDENTIFIER
+{
+  $$ = $1->find_type(current_scope, global_scope, false, current_lexer);
 }
         ;
 
@@ -1994,6 +1995,14 @@ simple_int_type:
         | KW_WCHAR_T
 {
   $$ = new CPPSimpleType(CPPSimpleType::T_wchar_t);
+}
+        | KW_CHAR16_T
+{
+  $$ = new CPPSimpleType(CPPSimpleType::T_char16_t);
+}
+        | KW_CHAR32_T
+{
+  $$ = new CPPSimpleType(CPPSimpleType::T_char32_t);
 }
         | KW_SHORT
 {
@@ -2132,7 +2141,8 @@ element:
         | SCOPE | PLUSPLUS | MINUSMINUS
         | TIMESEQUAL | DIVIDEEQUAL | MODEQUAL | PLUSEQUAL | MINUSEQUAL
         | OREQUAL | ANDEQUAL | XOREQUAL | LSHIFTEQUAL | RSHIFTEQUAL
-        | KW_BOOL | KW_CATCH | KW_CHAR | KW_WCHAR_T | KW_CLASS | KW_CONST
+        | KW_BOOL | KW_CATCH | KW_CHAR | KW_CHAR16_T | KW_CHAR32_T
+        | KW_WCHAR_T | KW_CLASS | KW_CONST
         | KW_DELETE | KW_DOUBLE | KW_DYNAMIC_CAST | KW_ELSE | KW_ENUM
         | KW_EXTERN | KW_EXPLICIT | KW_FALSE
         | KW_FLOAT | KW_FRIEND | KW_FOR | KW_GOTO
@@ -2369,6 +2379,18 @@ const_expr:
   CPPType *type =
     CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_wchar_t));
   $$ = new CPPExpression(CPPExpression::construct_op(type, $3));
+}
+        | KW_CHAR16_T '(' optional_const_expr_comma ')'
+{
+  CPPType *type =
+    CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char16_t));
+  $$ = new CPPExpression(CPPExpression::construct_op(type, $3));
+}
+        | KW_CHAR32_T '(' optional_const_expr_comma ')'
+{
+  CPPType *type =
+    CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_char32_t));
+  $$ = new CPPExpression(CPPExpression::construct_op(type, $3));
 }
         | KW_BOOL '(' optional_const_expr_comma ')'
 {

+ 25 - 4
dtool/src/cppparser/cppDeclaration.cxx

@@ -177,13 +177,13 @@ as_class_template_parameter() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CPPDeclaration::as_typedef
+//     Function: CPPDeclaration::as_typedef_type
 //       Access: Public, Virtual
 //  Description:
 ////////////////////////////////////////////////////////////////////
-CPPTypedef *CPPDeclaration::
-as_typedef() {
-  return (CPPTypedef *)NULL;
+CPPTypedefType *CPPDeclaration::
+as_typedef_type() {
+  return (CPPTypedefType *)NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -399,3 +399,24 @@ is_less(const CPPDeclaration *other) const {
   return this < other;
 }
 
+
+ostream &
+operator << (ostream &out, const CPPDeclaration::SubstDecl &subst) {
+  CPPDeclaration::SubstDecl::const_iterator it;
+  for (it = subst.begin(); it != subst.end(); ++it) {
+    out << "  ";
+    if (it->first == NULL) {
+      out << "(null)";
+    } else {
+      out << *(it->first);
+    }
+    out << " -> ";
+    if (it->second == NULL) {
+      out << "(null)";
+    } else {
+      out << *(it->second);
+    }
+    out << "\n";
+  }
+  return out;
+}

+ 6 - 3
dtool/src/cppparser/cppDeclaration.h

@@ -30,7 +30,7 @@ using namespace std;
 
 class CPPInstance;
 class CPPTemplateParameterList;
-class CPPTypedef;
+class CPPTypedefType;
 class CPPTypeDeclaration;
 class CPPExpression;
 class CPPType;
@@ -64,7 +64,6 @@ public:
   enum SubType {
     // Subtypes of CPPDeclaration
     ST_instance,
-    ST_typedef,
     ST_type_declaration,
     ST_expression,
     ST_type,
@@ -87,6 +86,7 @@ public:
     ST_class_template_parameter,
     ST_tbd,
     ST_type_proxy,
+    ST_typedef,
   };
 
   CPPDeclaration(const CPPFile &file);
@@ -120,7 +120,7 @@ public:
 
   virtual CPPInstance *as_instance();
   virtual CPPClassTemplateParameter *as_class_template_parameter();
-  virtual CPPTypedef *as_typedef();
+  virtual CPPTypedefType *as_typedef_type();
   virtual CPPTypeDeclaration *as_type_declaration();
   virtual CPPExpression *as_expression();
   virtual CPPType *as_type();
@@ -157,4 +157,7 @@ operator << (ostream &out, const CPPDeclaration &decl) {
   return out;
 }
 
+ostream &
+operator << (ostream &out, const CPPDeclaration::SubstDecl &decl);
+
 #endif

+ 100 - 12
dtool/src/cppparser/cppEnumType.cxx

@@ -13,7 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "cppEnumType.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppExpression.h"
 #include "cppSimpleType.h"
 #include "cppConstType.h"
@@ -24,14 +24,37 @@
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPEnumType::Constructor
 //       Access: Public
-//  Description:
+//  Description: Creates an untyped, unscoped enum.
 ////////////////////////////////////////////////////////////////////
 CPPEnumType::
 CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
             const CPPFile &file) :
   CPPExtensionType(T_enum, ident, current_scope, file),
+  _parent_scope(current_scope),
+  _element_type(NULL),
   _last_value(NULL)
 {
+  if (ident != NULL) {
+    ident->_native_scope = current_scope;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPEnumType::Constructor
+//       Access: Public
+//  Description: Creates a typed but unscoped enum.
+////////////////////////////////////////////////////////////////////
+CPPEnumType::
+CPPEnumType(CPPIdentifier *ident, CPPType *element_type,
+            CPPScope *current_scope, const CPPFile &file) :
+  CPPExtensionType(T_enum, ident, current_scope, file),
+  _parent_scope(current_scope),
+  _element_type(element_type),
+  _last_value(NULL)
+{
+  if (ident != NULL) {
+    ident->_native_scope = current_scope;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -41,12 +64,24 @@ CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
 ////////////////////////////////////////////////////////////////////
 CPPInstance *CPPEnumType::
 add_element(const string &name, CPPExpression *value) {
-  CPPType *type =
-    CPPType::new_type(new CPPConstType(new CPPSimpleType(
-      CPPSimpleType::T_int, CPPSimpleType::F_unsigned)));
-
   CPPIdentifier *ident = new CPPIdentifier(name);
-  CPPInstance *inst = new CPPInstance(type, ident);
+  ident->_native_scope = _parent_scope;
+  CPPInstance *inst;
+
+  static CPPType *default_element_type = NULL;
+  if (_element_type == NULL) {
+    // This enum is untyped.  Use a suitable default, ie. 'int'.
+    if (default_element_type == NULL) {
+      default_element_type =
+        CPPType::new_type(new CPPConstType(new CPPSimpleType(CPPSimpleType::T_int, 0)));
+    }
+
+    inst = new CPPInstance(default_element_type, ident);
+  } else {
+    // This enum has an explicit type, so use that.
+    inst = new CPPInstance(CPPType::new_type(new CPPConstType(_element_type)), ident);
+  }
+
   _elements.push_back(inst);
 
   if (value == (CPPExpression *)NULL) {
@@ -81,6 +116,38 @@ is_incomplete() const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPEnumType::is_fully_specified
+//       Access: Public, Virtual
+//  Description: Returns true if this declaration is an actual,
+//               factual declaration, or false if some part of the
+//               declaration depends on a template parameter which has
+//               not yet been instantiated.
+////////////////////////////////////////////////////////////////////
+bool CPPEnumType::
+is_fully_specified() const {
+  if (!CPPDeclaration::is_fully_specified()) {
+    return false;
+  }
+
+  if (_ident != NULL && !_ident->is_fully_specified()) {
+    return false;
+  }
+
+  if (_element_type != NULL && !_element_type->is_fully_specified()) {
+    return false;
+  }
+
+  Elements::const_iterator ei;
+  for (ei = _elements.begin(); ei != _elements.end(); ++ei) {
+    if (!(*ei)->is_fully_specified()) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPEnumType::substitute_decl
 //       Access: Public, Virtual
@@ -95,12 +162,34 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   }
 
   CPPEnumType *rep = new CPPEnumType(*this);
+
   if (_ident != NULL) {
     rep->_ident =
       _ident->substitute_decl(subst, current_scope, global_scope);
   }
 
-  if (rep->_ident == _ident) {
+  if (_element_type != NULL) {
+    rep->_element_type =
+      _element_type->substitute_decl(subst, current_scope, global_scope)
+      ->as_type();
+  }
+
+  bool any_changed = false;
+
+  for (int i = 0; i < _elements.size(); ++i) {
+    CPPInstance *elem_rep =
+      _elements[i]->substitute_decl(subst, current_scope, global_scope)
+      ->as_instance();
+
+    if (elem_rep != _elements[i]) {
+      rep->_elements[i] = elem_rep;
+      any_changed = true;
+    }
+  }
+
+  if (rep->_ident == _ident &&
+      rep->_element_type == _element_type &&
+      !any_changed) {
     delete rep;
     rep = this;
   }
@@ -124,15 +213,14 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
     }
     out << _ident->get_local_name(scope);
 
-  } else if (!complete && !_typedefs.empty()) {
-    // If we have a typedef name, use it.
-    out << _typedefs.front()->get_local_name(scope);
-
   } else {
     out << _type;
     if (_ident != NULL) {
       out << " " << _ident->get_local_name(scope);
     }
+    if (_element_type != NULL) {
+      out << " : " << _element_type->get_local_name(scope);
+    }
 
     out << " {\n";
     Elements::const_iterator ei;

+ 6 - 0
dtool/src/cppparser/cppEnumType.h

@@ -34,12 +34,15 @@ class CPPEnumType : public CPPExtensionType {
 public:
   CPPEnumType(CPPIdentifier *ident, CPPScope *current_scope,
               const CPPFile &file);
+  CPPEnumType(CPPIdentifier *ident, CPPType *element_type,
+              CPPScope *current_scope, const CPPFile &file);
 
   CPPInstance *add_element(const string &name,
                            CPPExpression *value = (CPPExpression *)NULL);
 
   virtual bool is_incomplete() const;
 
+  virtual bool is_fully_specified() const;
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
                                           CPPScope *current_scope,
                                           CPPScope *global_scope);
@@ -50,6 +53,9 @@ public:
 
   virtual CPPEnumType *as_enum_type();
 
+  CPPScope *_parent_scope;
+  CPPType *_element_type;
+
   typedef vector<CPPInstance *> Elements;
   Elements _elements;
   CPPExpression *_last_value;

+ 132 - 3
dtool/src/cppparser/cppExpression.cxx

@@ -147,6 +147,30 @@ as_pointer() const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExpression::Result::as_boolean
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+bool CPPExpression::Result::
+as_boolean() const {
+  switch (_type) {
+  case RT_integer:
+    return (_u._integer != 0);
+
+  case RT_real:
+    return (_u._real != 0.0);
+
+  case RT_pointer:
+    return (_u._pointer != NULL);
+
+  default:
+    cerr << "Invalid type\n";
+    assert(false);
+    return false;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPExpression::Result::output
 //       Access: Public
@@ -226,7 +250,7 @@ CPPExpression(CPPIdentifier *ident, CPPScope *current_scope,
   CPPDeclaration(CPPFile())
 {
   CPPDeclaration *decl =
-    ident->find_symbol(current_scope, global_scope, error_sink);
+    ident->find_symbol(current_scope, global_scope);
 
   if (decl != NULL) {
     CPPInstance *inst = decl->as_instance();
@@ -245,6 +269,7 @@ CPPExpression(CPPIdentifier *ident, CPPScope *current_scope,
 
   _type = T_unknown_ident;
   _u._ident = ident;
+  _u._ident->_native_scope = current_scope;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -801,6 +826,66 @@ determine_type() const {
   return NULL;  // Compiler kludge; can't get here.
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExpression::is_fully_specified
+//       Access: Public, Virtual
+//  Description: Returns true if this declaration is an actual,
+//               factual declaration, or false if some part of the
+//               declaration depends on a template parameter which has
+//               not yet been instantiated.
+////////////////////////////////////////////////////////////////////
+bool CPPExpression::
+is_fully_specified() const {
+  if (!CPPDeclaration::is_fully_specified()) {
+    return false;
+  }
+
+  switch (_type) {
+  case T_integer:
+  case T_real:
+  case T_string:
+    return false;
+
+  case T_variable:
+    return _u._variable->is_fully_specified();
+
+  case T_function:
+    return _u._fgroup->is_fully_specified();
+
+  case T_unknown_ident:
+    return _u._ident->is_fully_specified();
+
+  case T_typecast:
+  case T_construct:
+  case T_new:
+    return (_u._typecast._to->is_fully_specified() &&
+            _u._typecast._op1->is_fully_specified());
+
+  case T_default_construct:
+  case T_default_new:
+  case T_sizeof:
+    return _u._typecast._to->is_fully_specified();
+
+  case T_trinary_operation:
+    if (!_u._op._op3->is_fully_specified()) {
+      return false;
+    }
+    // Fall through
+
+  case T_binary_operation:
+    if (!_u._op._op2->is_fully_specified()) {
+      return false;
+    }
+    // Fall through
+
+  case T_unary_operation:
+    return _u._op._op1->is_fully_specified();
+
+  default:
+    return true;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPExpression::substitute_decl
 //       Access: Public, Virtual
@@ -827,6 +912,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
         // Replacing the variable reference with another variable reference.
         rep->_u._variable = decl->as_instance();
         any_changed = true;
+
       } else if (decl->as_expression()) {
         // Replacing the variable reference with an expression.
         delete rep;
@@ -836,6 +922,43 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
     }
     break;
 
+  case T_unknown_ident:
+    rep->_u._ident = _u._ident->substitute_decl(subst, current_scope, global_scope);
+    any_changed = any_changed || (rep->_u._ident != _u._ident);
+
+    // See if we can define it now.
+    decl = rep->_u._ident->find_symbol(current_scope, global_scope, subst);
+    if (decl != NULL) {
+      CPPInstance *inst = decl->as_instance();
+      if (inst != NULL) {
+        rep->_type = T_variable;
+        rep->_u._variable = inst;
+        any_changed = true;
+
+        decl = inst->substitute_decl(subst, current_scope, global_scope);
+        if (decl != inst) {
+          if (decl->as_instance()) {
+            // Replacing the variable reference with another variable reference.
+            rep->_u._variable = decl->as_instance();
+
+          } else if (decl->as_expression()) {
+            // Replacing the variable reference with an expression.
+            delete rep;
+            rep = decl->as_expression();
+          }
+        }
+        break;
+      }
+      CPPFunctionGroup *fgroup = decl->as_function_group();
+      if (fgroup != NULL) {
+        rep->_type = T_function;
+        rep->_u._fgroup = fgroup;
+        any_changed = true;
+      }
+    }
+
+    break;
+
   case T_typecast:
   case T_construct:
   case T_new:
@@ -909,6 +1032,9 @@ is_tbd() const {
 
     return true;
 
+  case T_unknown_ident:
+    return true;
+
   case T_typecast:
   case T_construct:
   case T_new:
@@ -996,8 +1122,12 @@ output(ostream &out, int indent_level, CPPScope *scope, bool) const {
     break;
 
   case T_variable:
+    // We can just refer to the variable by name, except if it's a
+    // private constant, in which case we have to compute the value,
+    // since we may have to use it in generated code.
     if (_u._variable->_type != NULL &&
-        _u._variable->_initializer != NULL) {
+        _u._variable->_initializer != NULL &&
+        _u._variable->_vis > V_public) {
       // A const variable.  Fetch its assigned value.
       CPPConstType *const_type = _u._variable->_type->as_const_type();
       if (const_type != NULL) {
@@ -1434,4 +1564,3 @@ is_less(const CPPDeclaration *other) const {
 
   return false;
 }
-

+ 2 - 0
dtool/src/cppparser/cppExpression.h

@@ -63,6 +63,7 @@ public:
     int as_integer() const;
     double as_real() const;
     void *as_pointer() const;
+    bool as_boolean() const;
     void output(ostream &out) const;
 
     ResultType _type;
@@ -78,6 +79,7 @@ public:
   CPPType *determine_type() const;
   bool is_tbd() const;
 
+  virtual bool is_fully_specified() const;
   virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
                                           CPPScope *current_scope,
                                           CPPScope *global_scope);

+ 24 - 1
dtool/src/cppparser/cppExtensionType.cxx

@@ -14,7 +14,7 @@
 
 
 #include "cppExtensionType.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppIdentifier.h"
 #include "cppParser.h"
 #include "indent.h"
@@ -130,6 +130,29 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   return rep;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPExtensionType::resolve_type
+//       Access: Public, Virtual
+//  Description: If this CPPType object is a forward reference or
+//               other nonspecified reference to a type that might now
+//               be known a real type, returns the real type.
+//               Otherwise returns the type itself.
+////////////////////////////////////////////////////////////////////
+CPPType *CPPExtensionType::
+resolve_type(CPPScope *current_scope, CPPScope *global_scope) {
+  if (_ident == NULL) {
+    // We can't resolve anonymous types.  But that's OK, since they
+    // can't be forward declared anyway.
+    return this;
+  }
+
+  // Maybe it has been defined by now.
+  CPPType *type = _ident->find_type(current_scope, global_scope);
+  if (type != NULL) {
+    return type;
+  }
+  return this;
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPExtensionType::is_equivalent_type

+ 6 - 1
dtool/src/cppparser/cppExtensionType.h

@@ -25,7 +25,9 @@ class CPPIdentifier;
 
 ///////////////////////////////////////////////////////////////////
 //       Class : CPPExtensionType
-// Description :
+// Description : Base class of enum, class, struct, and union types.
+//               An instance of the base class (instead of one of
+//               the specializations) is used for forward references.
 ////////////////////////////////////////////////////////////////////
 class CPPExtensionType : public CPPType {
 public:
@@ -50,6 +52,9 @@ public:
                                           CPPScope *current_scope,
                                           CPPScope *global_scope);
 
+  virtual CPPType *resolve_type(CPPScope *current_scope,
+                                CPPScope *global_scope);
+
   virtual bool is_equivalent(const CPPType &other) const;
 
 

+ 42 - 2
dtool/src/cppparser/cppIdentifier.cxx

@@ -39,7 +39,7 @@ CPPIdentifier(const string &name, const CPPFile &file) : _file(file) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 CPPIdentifier::
-CPPIdentifier(const CPPNameComponent &name) {
+CPPIdentifier(const CPPNameComponent &name, const CPPFile &file) : _file(file) {
   _names.push_back(name);
   _native_scope = (CPPScope *)NULL;
 }
@@ -146,8 +146,10 @@ get_local_name(CPPScope *scope) const {
 
   if (scope == NULL || (_native_scope == NULL && _names.size() == 1)) {
     result = _names.back().get_name_with_templ(scope);
+
   } else if (_names.front().empty()) {
     result = get_fully_scoped_name();
+
   } else {
     // Determine the scope of everything up until but not including the
     // last name.
@@ -382,6 +384,7 @@ find_type(CPPScope *current_scope, CPPScope *global_scope,
   if (scope == NULL) {
     return NULL;
   }
+
   CPPType *type = scope->find_type(get_simple_name(), subst, global_scope);
   if (type != NULL && _names.back().has_templ()) {
     // This is a template type.
@@ -398,7 +401,6 @@ find_type(CPPScope *current_scope, CPPScope *global_scope,
       assert(new_type != NULL);
       if (new_type == type) {
         type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this));
-        //      type = new_type;
       } else {
         type = new_type;
       }
@@ -424,12 +426,50 @@ find_symbol(CPPScope *current_scope, CPPScope *global_scope,
   if (scope == NULL) {
     return NULL;
   }
+
+  CPPDeclaration *sym;
+  if (!_names.back().has_templ()) {
+    sym = scope->find_symbol(get_simple_name());
+
+  } else {
+    sym = scope->find_template(get_simple_name());
+    if (sym != NULL) {
+      CPPType *type = sym->as_type();
+      if (type != NULL && type->is_incomplete()) {
+        // We can't instantiate an incomplete type.
+        sym = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this));
+      } else {
+        // Instantiate the symbol.
+        sym = sym->instantiate(_names.back().get_templ(), current_scope,
+                               global_scope, error_sink);
+      }
+    }
+  }
+
+  return sym;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPIdentifier::find_symbol
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPDeclaration *CPPIdentifier::
+find_symbol(CPPScope *current_scope, CPPScope *global_scope,
+            CPPDeclaration::SubstDecl &subst,
+            CPPPreprocessor *error_sink) const {
+  CPPScope *scope = get_scope(current_scope, global_scope, subst, error_sink);
+  if (scope == NULL) {
+    return NULL;
+  }
+
   CPPDeclaration *sym;
   if (!_names.back().has_templ()) {
     sym = scope->find_symbol(get_simple_name());
 
   } else {
     sym = scope->find_template(get_simple_name());
+
     if (sym != NULL) {
       CPPType *type = sym->as_type();
       if (type != NULL && type->is_incomplete()) {

+ 5 - 1
dtool/src/cppparser/cppIdentifier.h

@@ -36,7 +36,7 @@ class CPPTemplateParameterList;
 class CPPIdentifier {
 public:
   CPPIdentifier(const string &name, const CPPFile &file = CPPFile());
-  CPPIdentifier(const CPPNameComponent &name);
+  CPPIdentifier(const CPPNameComponent &name, const CPPFile &file = CPPFile());
   void add_name(const string &name);
   void add_name(const CPPNameComponent &name);
 
@@ -69,6 +69,10 @@ public:
   CPPDeclaration *find_symbol(CPPScope *current_scope,
                               CPPScope *global_scope,
                               CPPPreprocessor *error_sink = NULL) const;
+  CPPDeclaration *find_symbol(CPPScope *current_scope,
+                              CPPScope *global_scope,
+                              CPPDeclaration::SubstDecl &subst,
+                              CPPPreprocessor *error_sink = NULL) const;
   CPPDeclaration *find_template(CPPScope *current_scope,
                                 CPPScope *global_scope,
                                 CPPPreprocessor *error_sink = NULL) const;

+ 1 - 1
dtool/src/cppparser/cppInstance.cxx

@@ -372,6 +372,7 @@ CPPDeclaration *CPPInstance::
 instantiate(const CPPTemplateParameterList *actual_params,
             CPPScope *current_scope, CPPScope *global_scope,
             CPPPreprocessor *error_sink) const {
+
   if (!is_template()) {
     if (error_sink != NULL) {
       error_sink->warning("Ignoring template parameters for instance " +
@@ -457,7 +458,6 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   rep->_type = new_type->as_type();
 
   if (rep->_type == NULL) {
-    cerr << "Type " << *_type << " became " << *new_type << " which isn't a type\n";
     rep->_type = _type;
   }
 

+ 2 - 2
dtool/src/cppparser/cppManifest.cxx

@@ -47,8 +47,8 @@ ExpansionNode(const string &str, bool paste) :
 ////////////////////////////////////////////////////////////////////
 CPPManifest::
 CPPManifest(const string &args, const CPPFile &file) :
-  _file(file),
   _variadic_param(-1),
+  _file(file),
   _expr((CPPExpression *)NULL)
 {
   assert(!args.empty());
@@ -184,7 +184,7 @@ expand(const vector_string &args) const {
         // to a comma and no arguments are passed, the comma
         // is removed.  MSVC does this automatically.  Not sure
         // if we should allow MSVC behavior as well.
-        if (*result.rbegin() == ',') {
+        if (!result.empty() && *result.rbegin() == ',') {
           result.resize(result.size() - 1);
         }
       }

+ 24 - 10
dtool/src/cppparser/cppPreprocessor.cxx

@@ -200,6 +200,7 @@ CPPPreprocessor() {
 
   _warning_count = 0;
   _error_count = 0;
+  _error_abort = true;
 #ifdef CPP_VERBOSE_LEX
   _token_index = 0;
 #endif
@@ -404,8 +405,7 @@ get_next_token0() {
 
     int token_type = IDENTIFIER;
     CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope);
-    if (decl != NULL &&
-        (decl->as_typedef() != NULL || decl->as_type() != NULL)) {
+    if (decl != NULL && decl->as_type() != NULL) {
       token_type = TYPENAME_IDENTIFIER;
     }
 
@@ -432,10 +432,14 @@ warning(const string &message, int line, int col, CPPFile file) {
     if (file.empty()) {
       file = get_file();
     }
-    indent(cerr, _files.size() * 2)
+    int indent_level = 0;
+    if (_verbose >= 3) {
+      indent_level = _files.size() * 2;
+    }
+    indent(cerr, indent_level)
       << "*** Warning in " << file
       << " near line " << line << ", column " << col << ":\n";
-    indent(cerr, _files.size() * 2)
+    indent(cerr, indent_level)
       << message << "\n";
   }
   _warning_count++;
@@ -452,7 +456,7 @@ error(const string &message, int line, int col, CPPFile file) {
     // Don't report or log errors in the nested state.  These will be
     // reported when the nesting level collapses.
     return;
-  };
+  }
 
   if (_verbose >= 1) {
     if (line == 0) {
@@ -462,11 +466,20 @@ error(const string &message, int line, int col, CPPFile file) {
     if (file.empty()) {
       file = get_file();
     }
-    indent(cerr, _files.size() * 2)
+    int indent_level = 0;
+    if (_verbose >= 3) {
+      indent_level = _files.size() * 2;
+    }
+    indent(cerr, indent_level)
       << "*** Error in " << file
       << " near line " << line << ", column " << col << ":\n";
-    indent(cerr, _files.size() * 2)
+    indent(cerr, indent_level)
       << message << "\n";
+
+    if (_error_abort) {
+      cerr << "Aborting.\n";
+      abort();
+    }
   }
   _error_count++;
 }
@@ -603,7 +616,7 @@ init_type(const string &type) {
 ////////////////////////////////////////////////////////////////////
 bool CPPPreprocessor::
 push_file(const CPPFile &file) {
-  if (_verbose >= 2) {
+  if (_verbose >= 3) {
     indent(cerr, _files.size() * 2)
       << "Reading " << file << "\n";
   }
@@ -2009,7 +2022,8 @@ check_keyword(const string &name) {
   if (name == "bool") return KW_BOOL;
   if (name == "catch") return KW_CATCH;
   if (name == "char") return KW_CHAR;
-  if (name == "wchar_t") return KW_WCHAR_T;
+  if (name == "char16_t") return KW_CHAR16_T;
+  if (name == "char32_t") return KW_CHAR32_T;
   if (name == "class") return KW_CLASS;
   if (name == "const") return KW_CONST;
   if (name == "delete") return KW_DELETE;
@@ -2061,6 +2075,7 @@ check_keyword(const string &name) {
   if (name == "virtual") return KW_VIRTUAL;
   if (name == "void") return KW_VOID;
   if (name == "volatile") return KW_VOLATILE;
+  if (name == "wchar_t") return KW_WCHAR_T;
   if (name == "while") return KW_WHILE;
 
   // These are alternative ways to refer to built-in operators.
@@ -2287,7 +2302,6 @@ unget(int c) {
   _unget = c;
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPPreprocessor::nested_parse_template_instantiation
 //       Access: Private

+ 1 - 0
dtool/src/cppparser/cppPreprocessor.h

@@ -209,6 +209,7 @@ private:
 
   int _warning_count;
   int _error_count;
+  bool _error_abort;
 };
 
 #endif

+ 145 - 65
dtool/src/cppparser/cppScope.cxx

@@ -16,7 +16,7 @@
 #include "cppScope.h"
 #include "cppDeclaration.h"
 #include "cppNamespace.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppTypeDeclaration.h"
 #include "cppExtensionType.h"
 #include "cppInstance.h"
@@ -136,7 +136,7 @@ add_declaration(CPPDeclaration *decl, CPPScope *global_scope,
 
   _declarations.push_back(decl);
 
-  handle_declaration(decl, global_scope);
+  handle_declaration(decl, global_scope, preprocessor);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -185,9 +185,12 @@ add_enum_value(CPPInstance *inst, CPPPreprocessor *preprocessor,
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void CPPScope::
-define_extension_type(CPPExtensionType *type) {
+define_extension_type(CPPExtensionType *type, CPPPreprocessor *error_sink) {
   assert(type != NULL);
-  string name = type->get_simple_name();
+  string name = type->get_local_name(this);
+  if (name.empty()) {
+    return;
+  }
 
   switch (type->_type) {
   case CPPExtensionType::T_class:
@@ -204,31 +207,55 @@ define_extension_type(CPPExtensionType *type) {
 
   case CPPExtensionType::T_enum:
     _enums[name] = type;
+    break;
   }
 
   // Create an implicit typedef for the extension.
-  CPPIdentifier *ident = new CPPIdentifier(name);
-  CPPTypedef *td = new CPPTypedef(new CPPInstance(type, ident), false);
-  pair<Typedefs::iterator, bool> result =
-    _typedefs.insert(Typedefs::value_type(name, td));
+  //CPPTypedefType *td = new CPPTypedefType(type, name);
+  pair<Types::iterator, bool> result =
+    _types.insert(Types::value_type(name, type));
 
   if (!result.second) {
     // There's already a typedef for this extension.  This one
-    // overrides if it has template parameters and the other one
-    // doesn't.
-    CPPType *other_type = (*result.first).second->_type;
-    if (type->is_template() && !other_type->is_template()) {
-      (*result.first).second = td;
-
-      // Or if the other one is a forward reference.
-    } else if (other_type->get_subtype() == CPPDeclaration::ST_extension) {
-      (*result.first).second = td;
+    // overrides it only if the other is a forward declaration.
+    CPPType *other_type = (*result.first).second;
+
+    if (other_type->get_subtype() == CPPDeclaration::ST_extension) {
+      CPPExtensionType *other_ext = other_type->as_extension_type();
+
+      if (other_ext->_type != type->_type) {
+        if (error_sink != NULL) {
+          ostringstream errstr;
+          errstr << other_ext->_type << " " << type->get_fully_scoped_name()
+                 << " was previously declared as " << other_ext->_type << "\n";
+          error_sink->error(errstr.str());
+        }
+      }
+      (*result.first).second = type;
+
+    } else {
+      CPPTypedefType *other_td = other_type->as_typedef_type();
+
+      // Error out if the declaration is different than the previous one.
+      if (other_type != type &&
+          (other_td == NULL || other_td->_type != type)) {
+
+        if (error_sink != NULL) {
+          ostringstream errstr;
+          type->output(errstr, 0, NULL, false);
+          errstr << " has conflicting declaration as ";
+          other_type->output(errstr, 0, NULL, true);
+          error_sink->error(errstr.str());
+        }
+      }
     }
   }
 
   if (type->is_template()) {
+    string simple_name = type->get_simple_name();
+
     pair<Templates::iterator, bool> result =
-      _templates.insert(Templates::value_type(name, type));
+      _templates.insert(Templates::value_type(simple_name, type));
 
     if (!result.second) {
       // The template was not inserted because we already had a
@@ -278,7 +305,7 @@ add_using(CPPUsing *using_decl, CPPScope *global_scope,
   } else {
     CPPDeclaration *decl = using_decl->_ident->find_symbol(this, global_scope);
     if (decl != NULL) {
-      handle_declaration(decl, global_scope);
+      handle_declaration(decl, global_scope, error_sink);
     } else {
       if (error_sink != NULL) {
         error_sink->warning("Attempt to use unknown symbol: " + using_decl->_ident->get_fully_scoped_name());
@@ -392,11 +419,13 @@ instantiate(const CPPTemplateParameterList *actual_params,
       CPPDeclaration *decl = (*pi);
       CPPClassTemplateParameter *ctp = decl->as_class_template_parameter();
       if (ctp != NULL) {
-        CPPInstance *inst = new CPPInstance(ctp, ctp->_ident);
-        CPPTypedef *td = new CPPTypedef(inst, true);
-        scope->_typedefs.insert(Typedefs::value_type
-                                (ctp->_ident->get_local_name(),
-                                 td));
+        //CPPTypedefType *td = new CPPTypedefType(ctp, ctp->_ident);
+        //scope->_typedefs.insert(Typedefs::value_type
+        //                        (ctp->_ident->get_local_name(),
+        //                         td));
+        scope->_types.insert(Types::value_type
+                             (ctp->_ident->get_local_name(),
+                              ctp));
       }
     }
   }
@@ -466,10 +495,10 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
 ////////////////////////////////////////////////////////////////////
 CPPType *CPPScope::
 find_type(const string &name, bool recurse) const {
-  Typedefs::const_iterator ti;
-  ti = _typedefs.find(name);
-  if (ti != _typedefs.end()) {
-    return (*ti).second->_type;
+  Types::const_iterator ti;
+  ti = _types.find(name);
+  if (ti != _types.end()) {
+    return ti->second;
   }
 
   Using::const_iterator ui;
@@ -510,11 +539,11 @@ find_type(const string &name, bool recurse) const {
 CPPType *CPPScope::
 find_type(const string &name, CPPDeclaration::SubstDecl &subst,
           CPPScope *global_scope, bool recurse) const {
-  Typedefs::const_iterator ti;
-  ti = _typedefs.find(name);
-  if (ti != _typedefs.end()) {
+  Types::const_iterator ti;
+  ti = _types.find(name);
+  if (ti != _types.end()) {
     CPPScope *current_scope = (CPPScope *)this;
-    return (*ti).second->_type->substitute_decl
+    return (*ti).second->substitute_decl
       (subst, current_scope, global_scope)->as_type();
   }
 
@@ -563,10 +592,14 @@ find_scope(const string &name, bool recurse) const {
 
   CPPType *type = (CPPType *)NULL;
 
-  Typedefs::const_iterator ti;
-  ti = _typedefs.find(name);
-  if (ti != _typedefs.end()) {
-    type = (*ti).second->_type;
+  Types::const_iterator ti;
+  ti = _types.find(name);
+  if (ti != _types.end()) {
+    type = (*ti).second;
+    // Resolve if this is a typedef.
+    while (type->as_typedef_type() != (CPPTypedefType *)NULL) {
+      type = type->as_typedef_type()->_type;
+    }
 
   } else if (_struct_type != NULL) {
     CPPStructType::Derivation::const_iterator di;
@@ -614,10 +647,17 @@ find_scope(const string &name, CPPDeclaration::SubstDecl &subst,
   if (type == NULL) {
     return NULL;
   }
+
+  // Resolve this if it is a typedef.
+  while (type->get_subtype() == CPPDeclaration::ST_typedef) {
+    type = type->as_typedef_type()->_type;
+  }
+
   CPPStructType *st = type->as_struct_type();
   if (st == NULL) {
     return NULL;
   }
+
   return st->_scope;
 }
 
@@ -632,10 +672,10 @@ find_symbol(const string &name, bool recurse) const {
     return _struct_type;
   }
 
-  Typedefs::const_iterator ti;
-  ti = _typedefs.find(name);
-  if (ti != _typedefs.end()) {
-    return (*ti).second->_type;
+  Types::const_iterator ti;
+  ti = _types.find(name);
+  if (ti != _types.end()) {
+    return (*ti).second;
   }
 
   Variables::const_iterator vi;
@@ -756,9 +796,14 @@ get_local_name(CPPScope *scope) const {
   }
   */
 
-  if (scope != NULL && _parent_scope != NULL && _parent_scope != scope) {
-    return _parent_scope->get_local_name(scope) + "::" +
-      _name.get_name_with_templ();
+  if (scope != NULL && _parent_scope != NULL/* && _parent_scope != scope*/) {
+    string parent_scope_name = _parent_scope->get_local_name(scope);
+    if (parent_scope_name.empty()) {
+      return _name.get_name_with_templ();
+    } else {
+      return parent_scope_name + "::" +
+        _name.get_name_with_templ();
+    }
   } else {
     return _name.get_name_with_templ();
   }
@@ -817,8 +862,7 @@ write(ostream &out, int indent_level, CPPScope *scope) const {
     }
     bool complete = false;
 
-    if (cd->as_typedef() != NULL || cd->as_type() != NULL ||
-        cd->as_namespace() != NULL) {
+    if (cd->as_type() != NULL || cd->as_namespace() != NULL) {
       complete = true;
     }
 
@@ -881,7 +925,7 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
     }
     to_scope->_struct_type =
       new CPPStructType(_struct_type->_type,
-                        new CPPIdentifier(to_scope->_name),
+                        new CPPIdentifier(to_scope->_name, _struct_type->_file),
                         native_scope, to_scope, _struct_type->_file);
     to_scope->_struct_type->_incomplete = false;
 
@@ -986,11 +1030,11 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
     }
   }
 
-  Typedefs::const_iterator ti;
-  for (ti = _typedefs.begin(); ti != _typedefs.end(); ++ti) {
-    CPPTypedef *td =
-      (*ti).second->substitute_decl(subst, to_scope, global_scope)->as_typedef();
-    to_scope->_typedefs.insert(Typedefs::value_type((*ti).first, td));
+  Types::const_iterator ti;
+  for (ti = _types.begin(); ti != _types.end(); ++ti) {
+    CPPType *td =
+      (*ti).second->substitute_decl(subst, to_scope, global_scope)->as_type();
+    to_scope->_types.insert(Types::value_type((*ti).first, td));
     if (td != (*ti).second) {
       anything_changed = true;
     }
@@ -1000,6 +1044,19 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
     CPPInstance *inst =
       (*vi).second->substitute_decl(subst, to_scope, global_scope)->as_instance();
     to_scope->_variables.insert(Variables::value_type((*vi).first, inst));
+    if (inst != (*vi).second) {
+      // I don't know if this _native_scope assignment is right, but it
+      // fixes some issues with variables in instantiated template scopes
+      // being printed out with an uninstantiated template scope prefix. ~rdb
+      inst->_ident->_native_scope = to_scope;
+      anything_changed = true;
+    }
+  }
+
+  for (vi = _enum_values.begin(); vi != _enum_values.end(); ++vi) {
+    CPPInstance *inst =
+      (*vi).second->substitute_decl(subst, to_scope, global_scope)->as_instance();
+    to_scope->_enum_values.insert(Variables::value_type((*vi).first, inst));
     if (inst != (*vi).second) {
       anything_changed = true;
     }
@@ -1027,25 +1084,41 @@ copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
 //               functions, or whatever.
 ////////////////////////////////////////////////////////////////////
 void CPPScope::
-handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
-  CPPTypedef *def = decl->as_typedef();
+handle_declaration(CPPDeclaration *decl, CPPScope *global_scope,
+                   CPPPreprocessor *error_sink) {
+  CPPTypedefType *def = decl->as_typedef_type();
   if (def != NULL) {
     string name = def->get_simple_name();
-    _typedefs[name] = def;
+
+    pair<Types::iterator, bool> result =
+      _types.insert(Types::value_type(name, def));
+
+    if (!result.second) {
+      CPPType *other_type = result.first->second;
+      CPPTypedefType *other_td = other_type->as_typedef_type();
+
+      // We don't do redefinitions of typedefs.  But we don't complain
+      // as long as this is actually a typedef to the previous definition.
+      if (other_type != def->_type &&
+          (other_td == NULL || other_td->_type != def->_type)) {
+
+        if (error_sink != NULL) {
+          ostringstream errstr;
+          def->output(errstr, 0, NULL, false);
+          errstr << " has conflicting declaration as ";
+          other_type->output(errstr, 0, NULL, true);
+          error_sink->error(errstr.str());
+        }
+      }
+    } else {
+      _types[name] = def;
+    }
 
     CPPExtensionType *et = def->_type->as_extension_type();
     if (et != NULL) {
-      define_extension_type(et);
+      define_extension_type(et, error_sink);
     }
 
-    if (!name.empty() && def->get_scope(this, global_scope) == this) {
-      // Don't add a new template definition if we already had one
-      // by the same name in another scope.
-
-      if (find_template(name) == NULL) {
-        _templates.insert(Templates::value_type(name, def));
-      }
-    }
     return;
   }
 
@@ -1053,7 +1126,7 @@ handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
   if (typedecl != (CPPTypeDeclaration *)NULL) {
     CPPExtensionType *et = typedecl->_type->as_extension_type();
     if (et != NULL) {
-      define_extension_type(et);
+      define_extension_type(et, error_sink);
     }
     return;
   }
@@ -1062,6 +1135,13 @@ handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
   if (inst != NULL) {
     inst->check_for_constructor(this, global_scope);
 
+    if (inst->_ident != NULL) {
+      // Not sure if this is the best place to assign this.  However,
+      // this fixes a bug with variables in expressions not having
+      // the proper scoping prefix. ~rdb
+      inst->_ident->_native_scope = this;
+    }
+
     string name = inst->get_simple_name();
     if (!name.empty() && inst->get_scope(this, global_scope) == this) {
       if (inst->_type->as_function_type()) {
@@ -1108,6 +1188,6 @@ handle_declaration(CPPDeclaration *decl, CPPScope *global_scope) {
 
   CPPExtensionType *et = decl->as_extension_type();
   if (et != NULL) {
-    define_extension_type(et);
+    define_extension_type(et, error_sink);
   }
 }

+ 7 - 5
dtool/src/cppparser/cppScope.h

@@ -34,7 +34,7 @@ class CPPExtensionType;
 class CPPStructType;
 class CPPNamespace;
 class CPPUsing;
-class CPPTypedef;
+class CPPTypedefType;
 class CPPInstance;
 class CPPFunctionGroup;
 class CPPTemplateScope;
@@ -66,7 +66,8 @@ public:
   virtual void add_enum_value(CPPInstance *inst,
                               CPPPreprocessor *preprocessor,
                               const cppyyltype &pos);
-  virtual void define_extension_type(CPPExtensionType *type);
+  virtual void define_extension_type(CPPExtensionType *type,
+                                     CPPPreprocessor *error_sink = NULL);
   virtual void define_namespace(CPPNamespace *scope);
   virtual void add_using(CPPUsing *using_decl, CPPScope *global_scope,
                          CPPPreprocessor *error_sink = NULL);
@@ -113,7 +114,8 @@ private:
   copy_substitute_decl(CPPScope *to_scope, CPPDeclaration::SubstDecl &subst,
                        CPPScope *global_scope) const;
 
-  void handle_declaration(CPPDeclaration *decl, CPPScope *global_scope);
+  void handle_declaration(CPPDeclaration *decl, CPPScope *global_scope,
+                          CPPPreprocessor *error_sink = NULL);
 
 public:
   typedef vector<CPPDeclaration *> Declarations;
@@ -128,8 +130,8 @@ public:
   typedef map<string, CPPNamespace *> Namespaces;
   Namespaces _namespaces;
 
-  typedef map<string, CPPTypedef *> Typedefs;
-  Typedefs _typedefs;
+  typedef map<string, CPPType *> Types;
+  Types _types;
   typedef map<string, CPPInstance *> Variables;
   Variables _variables;
   Variables _enum_values;

+ 12 - 4
dtool/src/cppparser/cppSimpleType.cxx

@@ -99,6 +99,10 @@ output(ostream &out, int, CPPScope *, bool) const {
   }
 
   switch (_type) {
+  case T_unknown:
+    out << "unknown";
+    break;
+
   case T_bool:
     out << "bool";
     break;
@@ -111,6 +115,14 @@ output(ostream &out, int, CPPScope *, bool) const {
     out << "wchar_t";
     break;
 
+  case T_char16_t:
+    out << "char16_t";
+    break;
+
+  case T_char32_t:
+    out << "char32_t";
+    break;
+
   case T_int:
     out << "int";
     break;
@@ -127,10 +139,6 @@ output(ostream &out, int, CPPScope *, bool) const {
     out << "void";
     break;
 
-  case T_unknown:
-    out << "unknown";
-    break;
-
   case T_parameter:
     out << "parameter";
     break;

+ 4 - 2
dtool/src/cppparser/cppSimpleType.h

@@ -26,14 +26,16 @@
 class CPPSimpleType : public CPPType {
 public:
   enum Type {
+    T_unknown,
     T_bool,
     T_char,
-    T_wchar_t,  // Not strictly a builtin type, but we pretend.
+    T_wchar_t,
+    T_char16_t,
+    T_char32_t,
     T_int,
     T_float,
     T_double,
     T_void,
-    T_unknown,
 
     // T_parameter is a special type which is assigned to expressions
     // that are discovered where a formal parameter was expected.

+ 10 - 11
dtool/src/cppparser/cppStructType.cxx

@@ -14,7 +14,7 @@
 
 
 #include "cppStructType.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppScope.h"
 #include "cppTypeProxy.h"
 #include "cppTemplateScope.h"
@@ -91,6 +91,13 @@ operator = (const CPPStructType &copy) {
 void CPPStructType::
 append_derivation(CPPType *base, CPPVisibility vis, bool is_virtual) {
   if (base != NULL) {
+    // Unwrap any typedefs, since we can't inherit from a typedef.
+    CPPTypedefType *def = base->as_typedef_type();
+    while (def != NULL) {
+      base = def->_type;
+      def = base->as_typedef_type();
+    }
+
     Base b;
     b._base = base;
     b._vis = vis;
@@ -110,7 +117,6 @@ get_scope() const {
   return _scope;
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPStructType::is_abstract
 //       Access: Public
@@ -246,7 +252,7 @@ instantiate(const CPPTemplateParameterList *actual_params,
     // don't yet know what its associated struct type will be.
 
     // Postpone the evaluation of this type.
-    CPPIdentifier *ident = new CPPIdentifier(get_fully_scoped_name());
+    CPPIdentifier *ident = new CPPIdentifier(get_fully_scoped_name(), _file);
 
     return CPPType::new_type(new CPPTBDType(ident));
   }
@@ -318,7 +324,7 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
             rep->_template_scope = (CPPTemplateScope *)NULL;
             CPPNameComponent nc(get_simple_name());
             nc.set_templ(pscope->_name.get_templ());
-            rep->_ident = new CPPIdentifier(nc);
+            rep->_ident = new CPPIdentifier(nc, _file);
           }
         }
       }
@@ -356,7 +362,6 @@ substitute_decl(CPPDeclaration::SubstDecl &subst,
   assert(rep != NULL);
   if (rep != this) {
     _instantiations.insert(rep);
-    //    cerr << "Subst for " << *this << " is " << *rep << "\n";
   }
   return rep;
 }
@@ -377,15 +382,9 @@ output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
 
     if (is_template()) {
       CPPTemplateScope *tscope = get_template_scope();
-      out << "< ";
       tscope->_parameters.output(out, scope);
-      out << " >";
     }
 
-  } else if (!complete && !_typedefs.empty()) {
-    // If we have a typedef name, use it.
-    out << _typedefs.front()->get_local_name(scope);
-
   } else {
     if (is_template()) {
       get_template_scope()->_parameters.write_formal(out, scope);

+ 1 - 0
dtool/src/cppparser/cppTemplateParameterList.cxx

@@ -52,6 +52,7 @@ void CPPTemplateParameterList::
 build_subst_decl(const CPPTemplateParameterList &formal_params,
                  CPPDeclaration::SubstDecl &subst,
                  CPPScope *current_scope, CPPScope *global_scope) const {
+
   Parameters::const_iterator pfi, pai;
   for (pfi = formal_params._parameters.begin(), pai = _parameters.begin();
        pfi != formal_params._parameters.end() && pai != _parameters.end();

+ 5 - 4
dtool/src/cppparser/cppTemplateScope.cxx

@@ -17,7 +17,7 @@
 #include "cppExtensionType.h"
 #include "cppClassTemplateParameter.h"
 #include "cppIdentifier.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPTemplateScope::Constructor
@@ -64,10 +64,10 @@ add_enum_value(CPPInstance *inst, CPPPreprocessor *preprocessor,
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void CPPTemplateScope::
-define_extension_type(CPPExtensionType *type) {
+define_extension_type(CPPExtensionType *type, CPPPreprocessor *error_sink) {
   type->_template_scope = this;
   assert(_parent_scope != NULL);
-  _parent_scope->define_extension_type(type);
+  _parent_scope->define_extension_type(type, error_sink);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -105,8 +105,9 @@ add_template_parameter(CPPDeclaration *param) {
   if (cl != NULL) {
     // Create an implicit typedef for this class parameter.
     string name = cl->_ident->get_local_name();
-    _typedefs[name] = new CPPTypedef(new CPPInstance(cl, cl->_ident), false);
+    _types[name] = cl;
   }
+
   CPPInstance *inst = param->as_instance();
   if (inst != NULL) {
     // Register the variable for this value parameter.

+ 2 - 1
dtool/src/cppparser/cppTemplateScope.h

@@ -39,7 +39,8 @@ public:
   virtual void add_enum_value(CPPInstance *inst,
                               CPPPreprocessor *preprocessor,
                               const cppyyltype &pos);
-  virtual void define_extension_type(CPPExtensionType *type);
+  virtual void define_extension_type(CPPExtensionType *type,
+                                     CPPPreprocessor *error_sink = NULL);
   virtual void define_namespace(CPPNamespace *scope);
   virtual void add_using(CPPUsing *using_decl, CPPScope *global_scope,
                          CPPPreprocessor *error_sink = NULL);

+ 1 - 1
dtool/src/cppparser/cppType.cxx

@@ -14,7 +14,7 @@
 
 
 #include "cppType.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include <algorithm>
 
 CPPType::Types CPPType::_types;

+ 2 - 2
dtool/src/cppparser/cppType.h

@@ -22,7 +22,7 @@
 #include <set>
 
 class CPPType;
-class CPPTypedef;
+class CPPTypedefType;
 class CPPTypeDeclaration;
 
 
@@ -39,7 +39,7 @@ public:
 ////////////////////////////////////////////////////////////////////
 class CPPType : public CPPDeclaration {
 public:
-  typedef vector<CPPTypedef *> Typedefs;
+  typedef vector<CPPTypedefType *> Typedefs;
   Typedefs _typedefs;
 
   CPPType(const CPPFile &file);

+ 13 - 1
dtool/src/cppparser/cppTypeProxy.cxx

@@ -357,6 +357,19 @@ as_tbd_type() {
   return _actual_type->as_tbd_type();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypeProxy::as_typedef_type
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPTypedefType *CPPTypeProxy::
+as_typedef_type() {
+  if (_actual_type == (CPPType *)NULL) {
+    return (CPPTypedefType *)NULL;
+  }
+  return _actual_type->as_typedef_type();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPTypeProxy::as_type_proxy
 //       Access: Public, Virtual
@@ -366,4 +379,3 @@ CPPTypeProxy *CPPTypeProxy::
 as_type_proxy() {
   return this;
 }
-

+ 1 - 1
dtool/src/cppparser/cppTypeProxy.h

@@ -19,7 +19,6 @@
 
 #include "cppType.h"
 
-
 ///////////////////////////////////////////////////////////////////
 //       Class : CPPTypeProxy
 // Description : This is a special kind of type that is a placeholder
@@ -66,6 +65,7 @@ public:
   virtual CPPStructType *as_struct_type();
   virtual CPPEnumType *as_enum_type();
   virtual CPPTBDType *as_tbd_type();
+  virtual CPPTypedefType *as_typedef_type();
   virtual CPPTypeProxy *as_type_proxy();
 
   CPPType *_actual_type;

+ 0 - 91
dtool/src/cppparser/cppTypedef.cxx

@@ -1,91 +0,0 @@
-// Filename: cppTypedef.cxx
-// Created by:  drose (19Oct99)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
-
-
-#include "cppTypedef.h"
-
-////////////////////////////////////////////////////////////////////
-//     Function: CPPTypedef::Constructor
-//       Access: Public
-//  Description: Constructs a new CPPTypedef object based on the
-//               indicated CPPInstance object.  The CPPInstance is
-//               deallocated.
-//
-//               If global is true, the typedef is defined at the
-//               global scope, and hence it's worth telling the type
-//               itself about.  Otherwise, it's just a locally-scoped
-//               typedef.
-////////////////////////////////////////////////////////////////////
-CPPTypedef::
-CPPTypedef(CPPInstance *inst, bool global) : CPPInstance(*inst)
-{
-  // Actually, we'll avoid deleting this for now.  It causes problems
-  // for some reason to be determined later.
-  //  delete inst;
-
-  assert(_type != NULL);
-  if (global) {
-    _type->_typedefs.push_back(this);
-    CPPType::record_alt_name_for(_type, inst->get_local_name());
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CPPTypedef::substitute_decl
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-CPPDeclaration *CPPTypedef::
-substitute_decl(CPPDeclaration::SubstDecl &subst,
-                CPPScope *current_scope, CPPScope *global_scope) {
-  CPPDeclaration *decl =
-    CPPInstance::substitute_decl(subst, current_scope, global_scope);
-  assert(decl != NULL);
-  if (decl->as_typedef()) {
-    return decl;
-  }
-  assert(decl->as_instance() != NULL);
-  return new CPPTypedef(new CPPInstance(*decl->as_instance()), false);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CPPTypedef::output
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void CPPTypedef::
-output(ostream &out, int indent_level, CPPScope *scope, bool) const {
-  out << "typedef ";
-  CPPInstance::output(out, indent_level, scope, false);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CPPTypedef::get_subtype
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-CPPDeclaration::SubType CPPTypedef::
-get_subtype() const {
-  return ST_typedef;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: CPPTypedef::as_typedef
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-CPPTypedef *CPPTypedef::
-as_typedef() {
-  return this;
-}

+ 0 - 42
dtool/src/cppparser/cppTypedef.h

@@ -1,42 +0,0 @@
-// Filename: cppTypedef.h
-// Created by:  drose (19Oct99)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) Carnegie Mellon University.  All rights reserved.
-//
-// All use of this software is subject to the terms of the revised BSD
-// license.  You should have received a copy of this license along
-// with this source code in a file named "LICENSE."
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef CPPTYPEDEF_H
-#define CPPTYPEDEF_H
-
-#include "dtoolbase.h"
-
-#include "cppInstance.h"
-
-///////////////////////////////////////////////////////////////////
-//       Class : CPPTypedef
-// Description :
-////////////////////////////////////////////////////////////////////
-class CPPTypedef : public CPPInstance {
-public:
-  CPPTypedef(CPPInstance *instance, bool global);
-
-  virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
-                                          CPPScope *current_scope,
-                                          CPPScope *global_scope);
-
-  virtual void output(ostream &out, int indent_level, CPPScope *scope,
-                      bool complete) const;
-  virtual SubType get_subtype() const;
-
-  virtual CPPTypedef *as_typedef();
-};
-
-#endif
-

+ 388 - 0
dtool/src/cppparser/cppTypedefType.cxx

@@ -0,0 +1,388 @@
+// Filename: cppTypedefType.cxx
+// Created by:  rdb (01Aug14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "cppTypedefType.h"
+#include "cppIdentifier.h"
+#include "cppInstanceIdentifier.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPTypedefType::
+CPPTypedefType(CPPType *type, const string &name, CPPScope *current_scope) :
+  CPPType(CPPFile()),
+  _type(type),
+  _ident(new CPPIdentifier(name))
+{
+  if (_ident != NULL) {
+    _ident->_native_scope = current_scope;
+  }
+
+  _subst_decl_recursive_protect = false;
+
+  //assert(_type != NULL);
+  //if (global) {
+  //  _type->_typedefs.push_back(this);
+  //  CPPType::record_alt_name_for(_type, inst->get_local_name());
+  //}
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPTypedefType::
+CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope) :
+  CPPType(CPPFile()),
+  _type(type),
+  _ident(ident)
+{
+  if (_ident != NULL) {
+    _ident->_native_scope = current_scope;
+  }
+  _subst_decl_recursive_protect = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::Constructor
+//       Access: Public
+//  Description: Constructs a new CPPTypedefType object that defines a
+//               typedef to the indicated type according to the type
+//               and the InstanceIdentifier.  The InstanceIdentifier
+//               pointer is deallocated.
+////////////////////////////////////////////////////////////////////
+CPPTypedefType::
+CPPTypedefType(CPPType *type, CPPInstanceIdentifier *ii,
+               CPPScope *current_scope, const CPPFile &file) :
+  CPPType(file)
+{
+  _type = ii->unroll_type(type);
+  _ident = ii->_ident;
+  ii->_ident = NULL;
+  delete ii;
+
+  if (_ident != NULL) {
+    _ident->_native_scope = current_scope;
+  }
+
+  _subst_decl_recursive_protect = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::is_scoped
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+bool CPPTypedefType::
+is_scoped() const {
+  if (_ident == NULL) {
+    return false;
+  } else {
+    return _ident->is_scoped();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::get_scope
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPScope *CPPTypedefType::
+get_scope(CPPScope *current_scope, CPPScope *global_scope,
+          CPPPreprocessor *error_sink) const {
+  if (_ident == NULL) {
+    return current_scope;
+  } else {
+    return _ident->get_scope(current_scope, global_scope, error_sink);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::get_simple_name
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string CPPTypedefType::
+get_simple_name() const {
+  if (_ident == NULL) {
+    return "";
+  }
+  return _ident->get_simple_name();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::get_local_name
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string CPPTypedefType::
+get_local_name(CPPScope *scope) const {
+  if (_ident == NULL) {
+    return "";
+  }
+  return _ident->get_local_name(scope);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::get_fully_scoped_name
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string CPPTypedefType::
+get_fully_scoped_name() const {
+  if (_ident == NULL) {
+    return "";
+  }
+  return _ident->get_fully_scoped_name();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::is_incomplete
+//       Access: Public, Virtual
+//  Description: Returns true if the type has not yet been fully
+//               specified, false if it has.
+////////////////////////////////////////////////////////////////////
+bool CPPTypedefType::
+is_incomplete() const {
+  return false;
+  //return _type->is_incomplete();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::is_tbd
+//       Access: Public, Virtual
+//  Description: Returns true if the type, or any nested type within
+//               the type, is a CPPTBDType and thus isn't fully
+//               determined right now.  In this case, calling
+//               resolve_type() may or may not resolve the type.
+////////////////////////////////////////////////////////////////////
+bool CPPTypedefType::
+is_tbd() const {
+  if (_ident != NULL && _ident->is_tbd()) {
+    return true;
+  }
+  return _type->is_tbd();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::is_fully_specified
+//       Access: Public, Virtual
+//  Description: Returns true if this declaration is an actual,
+//               factual declaration, or false if some part of the
+//               declaration depends on a template parameter which has
+//               not yet been instantiated.
+////////////////////////////////////////////////////////////////////
+bool CPPTypedefType::
+is_fully_specified() const {
+  if (_ident != NULL && !_ident->is_fully_specified()) {
+    return false;
+  }
+  return CPPDeclaration::is_fully_specified() &&
+    _type->is_fully_specified();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::substitute_decl
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPDeclaration *CPPTypedefType::
+substitute_decl(CPPDeclaration::SubstDecl &subst,
+                CPPScope *current_scope, CPPScope *global_scope) {
+
+  return _type->substitute_decl(subst, current_scope, global_scope);
+
+  // Bah, this doesn't seem to work, and I can't figure out why.
+  // Well, for now, let's just substitute it with the type we're
+  // pointing to.  This is not a huge deal for now, until we find
+  // that we need to preserve these typedefs.
+
+  /*
+  CPPDeclaration *top =
+    CPPType::substitute_decl(subst, current_scope, global_scope);
+  if (top != this) {
+    return top;
+  }
+
+  if (_subst_decl_recursive_protect) {
+    // We're already executing this block; we'll have to return a
+    // proxy to the type which we'll define later.
+    CPPTypeProxy *proxy = new CPPTypeProxy;
+    _proxies.push_back(proxy);
+    assert(proxy != NULL);
+    return proxy;
+  }
+  _subst_decl_recursive_protect = true;
+
+  CPPTypedefType *rep = new CPPTypedefType(*this);
+  CPPDeclaration *new_type =
+    _type->substitute_decl(subst, current_scope, global_scope);
+  rep->_type = new_type->as_type();
+
+  if (rep->_type == NULL) {
+    rep->_type = _type;
+  }
+
+  if (_ident != NULL) {
+    rep->_ident =
+      _ident->substitute_decl(subst, current_scope, global_scope);
+  }
+
+  if (rep->_type == _type && rep->_ident == _ident) {
+    delete rep;
+    rep = this;
+  }
+
+  rep = CPPType::new_type(rep)->as_typedef_type();
+  subst.insert(SubstDecl::value_type(this, rep));
+
+  _subst_decl_recursive_protect = false;
+  // Now fill in all the proxies we created for our recursive
+  // references.
+  Proxies::iterator pi;
+  for (pi = _proxies.begin(); pi != _proxies.end(); ++pi) {
+    (*pi)->_actual_type = rep;
+  }
+
+  return rep; */
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPFunctionType::resolve_type
+//       Access: Public, Virtual
+//  Description: If this CPPType object is a forward reference or
+//               other nonspecified reference to a type that might now
+//               be known a real type, returns the real type.
+//               Otherwise returns the type itself.
+////////////////////////////////////////////////////////////////////
+CPPType *CPPTypedefType::
+resolve_type(CPPScope *current_scope, CPPScope *global_scope) {
+  CPPType *ptype = _type->resolve_type(current_scope, global_scope);
+
+  if (ptype != _type) {
+    CPPTypedefType *rep = new CPPTypedefType(*this);
+    rep->_type = ptype;
+    return CPPType::new_type(rep);
+  }
+
+  return this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::is_equivalent_type
+//       Access: Public, Virtual
+//  Description: This is a little more forgiving than is_equal(): it
+//               returns true if the types appear to be referring to
+//               the same thing, even if they may have different
+//               pointers or somewhat different definitions.  It's
+//               useful for parameter matching, etc.
+////////////////////////////////////////////////////////////////////
+bool CPPTypedefType::
+is_equivalent(const CPPType &other) const {
+  CPPType *ot = (CPPType *)&other;
+
+  // Unwrap all the typedefs to get to where it is pointing.
+  while (ot->get_subtype() == ST_typedef) {
+    ot = ot->as_typedef_type()->_type;
+  }
+
+  // Compare the unwrapped type to what we are pointing to.
+  // If we are pointing to a typedef ourselves, then this will
+  // automatically recurse.
+  return _type->is_equivalent(*ot);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::output
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void CPPTypedefType::
+output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
+  string name;
+  if (_ident != NULL) {
+    name = _ident->get_local_name(scope);
+  }
+
+  if (complete) {
+    out << "typedef ";
+    _type->output_instance(out, indent_level, scope, false, "", name);
+  } else {
+    out << name;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::get_subtype
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPDeclaration::SubType CPPTypedefType::
+get_subtype() const {
+  return ST_typedef;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::as_typedef_type
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPTypedefType *CPPTypedefType::
+as_typedef_type() {
+  return this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::is_equal
+//       Access: Protected, Virtual
+//  Description: Called by CPPDeclaration() to determine whether this type is
+//               equivalent to another type of the same type.
+////////////////////////////////////////////////////////////////////
+bool CPPTypedefType::
+is_equal(const CPPDeclaration *other) const {
+  const CPPTypedefType *ot = ((CPPDeclaration *)other)->as_typedef_type();
+  assert(ot != NULL);
+
+  return (_type == ot->_type) && (*_ident == *ot->_ident);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPTypedefType::is_less
+//       Access: Protected, Virtual
+//  Description: Called by CPPDeclaration() to determine whether this type
+//               should be ordered before another type of the same
+//               type, in an arbitrary but fixed ordering.
+////////////////////////////////////////////////////////////////////
+bool CPPTypedefType::
+is_less(const CPPDeclaration *other) const {
+  return CPPDeclaration::is_less(other);
+
+  // The below code causes a crash for unknown reasons.
+  /*
+  const CPPTypedefType *ot = ((CPPDeclaration *)other)->as_typedef_type();
+  assert(ot != NULL);
+
+  if (_type != ot->_type) {
+    return _type < ot->_type;
+  }
+
+  if (*_ident != *ot->_ident) {
+    return *_ident < *ot->_ident;
+  }
+
+  return false; */
+}

+ 74 - 0
dtool/src/cppparser/cppTypedefType.h

@@ -0,0 +1,74 @@
+// Filename: cppTypedefType.h
+// Created by:  rdb (01Aug14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CPPTYPEDEFTYPE_H
+#define CPPTYPEDEFTYPE_H
+
+#include "dtoolbase.h"
+#include "cppType.h"
+
+class CPPIdentifier;
+
+///////////////////////////////////////////////////////////////////
+//       Class : CPPTypedefType
+// Description :
+////////////////////////////////////////////////////////////////////
+class CPPTypedefType : public CPPType {
+public:
+  CPPTypedefType(CPPType *type, const string &name, CPPScope *current_scope);
+  CPPTypedefType(CPPType *type, CPPIdentifier *ident, CPPScope *current_scope);
+  CPPTypedefType(CPPType *type, CPPInstanceIdentifier *ii,
+                 CPPScope *current_scope, const CPPFile &file);
+
+  bool is_scoped() const;
+  CPPScope *get_scope(CPPScope *current_scope, CPPScope *global_scope,
+                      CPPPreprocessor *error_sink = NULL) const;
+
+  virtual string get_simple_name() const;
+  virtual string get_local_name(CPPScope *scope = NULL) const;
+  virtual string get_fully_scoped_name() const;
+
+  virtual bool is_incomplete() const;
+  virtual bool is_tbd() const;
+
+  virtual bool is_fully_specified() const;
+
+  virtual CPPDeclaration *substitute_decl(SubstDecl &subst,
+                                          CPPScope *current_scope,
+                                          CPPScope *global_scope);
+
+  virtual CPPType *resolve_type(CPPScope *current_scope,
+                                CPPScope *global_scope);
+
+  virtual bool is_equivalent(const CPPType &other) const;
+
+  virtual void output(ostream &out, int indent_level, CPPScope *scope,
+                      bool complete) const;
+  virtual SubType get_subtype() const;
+
+  virtual CPPTypedefType *as_typedef_type();
+
+  CPPType *_type;
+  CPPIdentifier *_ident;
+
+protected:
+  virtual bool is_equal(const CPPDeclaration *other) const;
+  virtual bool is_less(const CPPDeclaration *other) const;
+
+  bool _subst_decl_recursive_protect;
+  typedef vector<CPPTypeProxy *> Proxies;
+  Proxies _proxies;
+};
+
+#endif

+ 1 - 6
dtool/src/cppparser/p3cppParser_composite1.cxx

@@ -18,13 +18,8 @@
 #include "cppTypeDeclaration.cxx"
 #include "cppTypeParser.cxx"
 #include "cppTypeProxy.cxx"
+#include "cppTypedefType.cxx"
 #include "cppSimpleType.cxx"
 #include "cppTBDType.cxx"
-#include "cppTypedef.cxx"
 #include "cppUsing.cxx"
 #include "cppVisibility.cxx"
-
-
-
-
-

+ 9 - 1
dtool/src/dtoolbase/atomicAdjust.h

@@ -18,7 +18,15 @@
 #include "dtoolbase.h"
 #include "selectThreadImpl.h"
 
-#if defined(THREAD_DUMMY_IMPL)||defined(THREAD_SIMPLE_IMPL)
+#if defined(CPPPARSER)
+
+struct AtomicAdjust {
+  typedef long Integer;
+  typedef void *UnalignedPointer;
+  typedef UnalignedPointer Pointer;
+};
+
+#elif defined(THREAD_DUMMY_IMPL) || defined(THREAD_SIMPLE_IMPL)
 
 #include "atomicAdjustDummyImpl.h"
 typedef AtomicAdjustDummyImpl AtomicAdjust;

+ 4 - 25
dtool/src/dtoolbase/typeHandle.cxx

@@ -16,33 +16,9 @@
 #include "typeRegistryNode.h"
 #include "atomicAdjust.h"
 
-#ifdef HAVE_PYTHON
-#include "Python.h"
-#endif
-
 // This is initialized to zero by static initialization.
 TypeHandle TypeHandle::_none;
 
-#ifdef HAVE_PYTHON
-////////////////////////////////////////////////////////////////////
-//     Function: TypeHandle::make
-//       Access: Published
-//  Description: This special method allows coercion to a TypeHandle
-//               from a Python class object or instance.  It simply
-//               attempts to call classobj.get_class_type(), and
-//               returns that value (or raises an exception if that
-//               method doesn't work).
-//
-//               This method allows a Python class object to be used
-//               anywhere a TypeHandle is expected by the C++
-//               interface.
-////////////////////////////////////////////////////////////////////
-PyObject *TypeHandle::
-make(PyObject *classobj) {
-  return PyObject_CallMethod(classobj, (char *)"get_class_type", (char *)"");
-}
-#endif  // HAVE_PYTHON
-
 #ifdef DO_MEMORY_USAGE
 ////////////////////////////////////////////////////////////////////
 //     Function: TypeHandle::get_memory_usage
@@ -80,7 +56,10 @@ inc_memory_usage(MemoryClass memory_class, int size) {
     assert(rnode != (TypeRegistryNode *)NULL);
     AtomicAdjust::add(rnode->_memory_usage[memory_class], (AtomicAdjust::Integer)size);
     //cerr << *this << ".inc(" << memory_class << ", " << size << ") -> " << rnode->_memory_usage[memory_class] << "\n";
-    assert(rnode->_memory_usage[memory_class] >= 0);
+    if (rnode->_memory_usage[memory_class] < 0) {
+      cerr << "Memory usage overflow for type " << *this << ".\n";
+      abort();
+    }
   }
 }
 #endif  // DO_MEMORY_USAGE

+ 1 - 10
dtool/src/dtoolbase/typeHandle.h

@@ -64,13 +64,6 @@
 
 class TypedObject;
 
-#ifdef HAVE_PYTHON
-#ifndef PyObject_HEAD
-struct _object;
-typedef _object PyObject;
-#endif
-#endif
-
 ////////////////////////////////////////////////////////////////////
 //       Class : TypeHandle
 // Description : TypeHandle is the identifier used to differentiate
@@ -104,9 +97,7 @@ PUBLISHED:
   INLINE TypeHandle();
   INLINE TypeHandle(const TypeHandle &copy);
 
-#ifdef HAVE_PYTHON
-  static PyObject *make(PyObject *classobj);
-#endif  // HAVE_PYTHON
+  EXTENSION(static TypeHandle make(PyTypeObject *classobj));
 
   INLINE bool operator == (const TypeHandle &other) const;
   INLINE bool operator != (const TypeHandle &other) const;

+ 5 - 0
dtool/src/dtoolutil/Sources.pp

@@ -17,6 +17,8 @@
     filename.h \
     $[if $[IS_OSX],filename_assist.mm filename_assist.h,] \
     globPattern.I globPattern.h \
+    lineStream.I lineStream.h \
+    lineStreamBuf.I lineStreamBuf.h \
     load_dso.h \
     pandaFileStream.h pandaFileStream.I \
     pandaFileStreamBuf.h \
@@ -38,6 +40,7 @@
     dSearchPath.cxx \
     executionEnvironment.cxx filename.cxx \
     globPattern.cxx \
+    lineStream.cxx lineStreamBuf.cxx \
     load_dso.cxx  \
     pandaFileStream.cxx pandaFileStreamBuf.cxx \
     pandaSystem.cxx \
@@ -58,6 +61,8 @@
     executionEnvironment.I executionEnvironment.h filename.I \
     filename.h \
     globPattern.I globPattern.h \
+    lineStream.I lineStream.h \
+    lineStreamBuf.I lineStreamBuf.h \
     load_dso.h \
     pandaFileStream.h pandaFileStream.I \
     pandaFileStreamBuf.h \

+ 11 - 0
dtool/src/dtoolutil/filename.I

@@ -375,6 +375,17 @@ operator + (const string &other) const {
   return a;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Filename::operator /
+//       Access: Published
+//  Description: Returns a new Filename that is composed of the
+//               other filename added to the end of this filename,
+//               with an intervening slash added if necessary.
+////////////////////////////////////////////////////////////////////
+INLINE Filename Filename::
+operator / (const Filename &other) const {
+  return Filename(*this, other);
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Filename::get_fullpath

+ 1 - 61
dtool/src/dtoolutil/filename.cxx

@@ -308,30 +308,6 @@ Filename(const Filename &dirname, const Filename &basename) {
   }
 }
 
-#ifdef HAVE_PYTHON
-////////////////////////////////////////////////////////////////////
-//     Function: Filename::__reduce__
-//       Access: Published
-//  Description: This special Python method is implement to provide
-//               support for the pickle module.
-////////////////////////////////////////////////////////////////////
-PyObject *Filename::
-__reduce__(PyObject *self) const {
-  // We should return at least a 2-tuple, (Class, (args)): the
-  // necessary class object whose constructor we should call
-  // (e.g. this), and the arguments necessary to reconstruct this
-  // object.
-  PyObject *this_class = PyObject_Type(self);
-  if (this_class == NULL) {
-    return NULL;
-  }
-
-  PyObject *result = Py_BuildValue("(O(s))", this_class, c_str());
-  Py_DECREF(this_class);
-  return result;
-}
-#endif  // HAVE_PYTHON
-
 ////////////////////////////////////////////////////////////////////
 //     Function: Filename::from_os_specific
 //       Access: Published, Static
@@ -2005,49 +1981,13 @@ scan_directory(vector_string &contents) const {
   globfree(&globbuf);
 
   return true;
-  
+
 #else
   // Don't know how to scan directories!
   return false;
 #endif
 }
 
-#ifdef HAVE_PYTHON
-////////////////////////////////////////////////////////////////////
-//     Function: Filename::scan_directory
-//       Access: Published
-//  Description: This variant on scan_directory returns a Python list
-//               of strings on success, or None on failure.
-////////////////////////////////////////////////////////////////////
-PyObject *Filename::
-scan_directory() const {
-  vector_string contents;
-  if (!scan_directory(contents)) {
-    PyObject *result = Py_None;
-    Py_INCREF(result);
-    return result;
-  }
-
-  PyObject *result = PyList_New(contents.size());
-  for (size_t i = 0; i < contents.size(); ++i) {
-    const string &filename = contents[i];
-#if PY_MAJOR_VERSION >= 3
-    // This function expects UTF-8.
-    PyObject *str = PyUnicode_FromStringAndSize(filename.data(), filename.size());
-#else
-    PyObject *str = PyString_FromStringAndSize(filename.data(), filename.size());
-#endif
-#ifdef Py_LIMITED_API
-    PyList_SetItem(result, i, str);
-#else
-    PyList_SET_ITEM(result, i, str);
-#endif
-  }
-
-  return result;
-}
-#endif  // HAVE_PYTHON
-
 ////////////////////////////////////////////////////////////////////
 //     Function: Filename::open_read
 //       Access: Published

+ 6 - 4
dtool/src/dtoolutil/filename.h

@@ -74,7 +74,7 @@ PUBLISHED:
 #endif
 
 #ifdef HAVE_PYTHON
-  PyObject *__reduce__(PyObject *self) const;
+  EXTENSION(PyObject *__reduce__(PyObject *self) const);
 #endif
 
   // Static constructors to explicitly create a filename that refers
@@ -126,6 +126,8 @@ PUBLISHED:
   INLINE void operator += (const string &other);
   INLINE Filename operator + (const string &other) const;
 
+  INLINE Filename operator / (const Filename &other) const;
+
   // Or, you can use any of these.
   INLINE string get_fullpath() const;
   INLINE wstring get_fullpath_w() const;
@@ -200,11 +202,11 @@ PUBLISHED:
                         const string &default_extension = string());
   bool make_relative_to(Filename directory, bool allow_backups = true);
   int find_on_searchpath(const DSearchPath &searchpath);
-  
+
   bool scan_directory(vector_string &contents) const;
 #ifdef HAVE_PYTHON
-  PyObject *scan_directory() const;
-#endif 
+  EXTENSION(PyObject *scan_directory() const);
+#endif
 
   bool open_read(ifstream &stream) const;
   bool open_write(ofstream &stream, bool truncate = true) const;

+ 7 - 39
dtool/src/dtoolutil/globPattern.cxx

@@ -113,44 +113,12 @@ match_files(vector_string &results, const Filename &cwd) const {
     pattern = source.substr(0, slash);
     suffix = source.substr(slash + 1);
   }
-  
+
   GlobPattern glob(pattern);
   glob.set_case_sensitive(_case_sensitive);
   return glob.r_match_files(prefix, suffix, results, cwd);
 }
 
-#ifdef HAVE_PYTHON
-////////////////////////////////////////////////////////////////////
-//     Function: GlobPattern::match_files
-//       Access: Published
-//  Description: This variant on match_files returns a Python list
-//               of strings.
-////////////////////////////////////////////////////////////////////
-PyObject *GlobPattern::
-match_files(const Filename &cwd) const {
-  vector_string contents;
-  match_files(contents, cwd);
-
-  PyObject *result = PyList_New(contents.size());
-  for (size_t i = 0; i < contents.size(); ++i) {
-    const string &filename = contents[i];
-#if PY_MAJOR_VERSION >= 3
-    // This function expects UTF-8.
-    PyObject *str = PyUnicode_FromStringAndSize(filename.data(), filename.size());
-#else
-    PyObject *str = PyString_FromStringAndSize(filename.data(), filename.size());
-#endif
-#ifdef Py_LIMITED_API
-    PyList_SetItem(result, i, str);
-#else
-    PyList_SET_ITEM(result, i, str);
-#endif
-  }
-
-  return result;
-}
-#endif  // HAVE_PYTHON
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GlobPattern::r_match_files
 //       Access: Private
@@ -195,21 +163,21 @@ r_match_files(const Filename &prefix, const string &suffix,
     return next_glob.r_match_files(Filename(prefix, _pattern),
                                    next_suffix, results, cwd);
 
-  } 
+  }
 
   // If there *are* special glob characters, we must attempt to
   // match the pattern against the files in this directory.
-  
+
   vector_string dir_files;
   if (!parent_dir.scan_directory(dir_files)) {
     // Not a directory, or unable to read directory; stop here.
     return 0;
   }
-  
+
   // Now go through each file in the directory looking for one that
   // matches the pattern.
   int num_matched = 0;
-  
+
   vector_string::const_iterator fi;
   for (fi = dir_files.begin(); fi != dir_files.end(); ++fi) {
     const string &local_file = (*fi);
@@ -218,7 +186,7 @@ r_match_files(const Filename &prefix, const string &suffix,
         // We have a match; continue.
         if (suffix.empty()) {
           results.push_back(Filename(prefix, local_file));
-          num_matched++; 
+          num_matched++;
         } else {
           num_matched += next_glob.r_match_files(Filename(prefix, local_file),
                                                  next_suffix, results, cwd);
@@ -226,7 +194,7 @@ r_match_files(const Filename &prefix, const string &suffix,
       }
     }
   }
-  
+
   return num_matched;
 }
 

+ 2 - 2
dtool/src/dtoolutil/globPattern.h

@@ -61,8 +61,8 @@ PUBLISHED:
   string get_const_prefix() const;
   int match_files(vector_string &results, const Filename &cwd = Filename()) const;
 #ifdef HAVE_PYTHON
-  PyObject *match_files(const Filename &cwd = Filename()) const;
-#endif 
+  EXTENSION(PyObject *match_files(const Filename &cwd = Filename()) const);
+#endif
 
 private:
   bool matches_substr(string::const_iterator pi,

+ 0 - 0
panda/src/putil/lineStream.I → dtool/src/dtoolutil/lineStream.I


+ 0 - 0
panda/src/putil/lineStream.cxx → dtool/src/dtoolutil/lineStream.cxx


+ 2 - 2
panda/src/putil/lineStream.h → dtool/src/dtoolutil/lineStream.h

@@ -15,7 +15,7 @@
 #ifndef LINESTREAM_H
 #define LINESTREAM_H
 
-#include "pandabase.h"
+#include "dtoolbase.h"
 
 #include "lineStreamBuf.h"
 
@@ -33,7 +33,7 @@
 //               More text can still be written to it and continuously
 //               extracted.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_PUTIL LineStream : public ostream {
+class EXPCL_DTOOL LineStream : public ostream {
 PUBLISHED:
   INLINE LineStream();
 

+ 0 - 0
panda/src/putil/lineStreamBuf.I → dtool/src/dtoolutil/lineStreamBuf.I


+ 0 - 0
panda/src/putil/lineStreamBuf.cxx → dtool/src/dtoolutil/lineStreamBuf.cxx


+ 2 - 2
panda/src/putil/lineStreamBuf.h → dtool/src/dtoolutil/lineStreamBuf.h

@@ -15,7 +15,7 @@
 #ifndef LINESTREAMBUF_H
 #define LINESTREAMBUF_H
 
-#include "pandabase.h"
+#include "dtoolbase.h"
 
 #include <string>
 
@@ -26,7 +26,7 @@
 //               continuously extracted as a sequence of lines of
 //               text.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA_PUTIL LineStreamBuf : public streambuf {
+class EXPCL_DTOOL LineStreamBuf : public streambuf {
 public:
   LineStreamBuf();
   virtual ~LineStreamBuf();

+ 2 - 0
dtool/src/dtoolutil/p3dtoolutil_composite1.cxx

@@ -4,6 +4,8 @@
 #include "executionEnvironment.cxx"
 #include "filename.cxx"
 #include "globPattern.cxx"
+#include "lineStream.cxx"
+#include "lineStreamBuf.cxx"
 #include "load_dso.cxx"
 #include "pandaSystem.cxx"
 

+ 130 - 21
dtool/src/interrogate/functionRemap.cxx

@@ -17,6 +17,7 @@
 #include "interrogate.h"
 #include "parameterRemap.h"
 #include "parameterRemapThis.h"
+#include "parameterRemapUnchanged.h"
 #include "interfaceMaker.h"
 #include "interrogateBuilder.h"
 
@@ -200,7 +201,7 @@ call_function(ostream &out, int indent_level, bool convert_result,
 
       // 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 case, we might inadvertently generate code like "return
       // &(*this)", when "return this" would do.  We check for this here
       // and undo it as a special case.
 
@@ -226,7 +227,8 @@ call_function(ostream &out, int indent_level, bool convert_result,
       return_expr = get_call_str(container, pexprs);
 
     } else {
-      if (_return_type->return_value_should_be_simple()) {
+      //if (_return_type->return_value_should_be_simple()) {
+      if (false) {
         // 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);
@@ -234,8 +236,14 @@ call_function(ostream &out, int indent_level, bool convert_result,
                                                            &parser);
         out << " = " << call << ";\n";
 
+        // MOVE() expands to std::move() when we are compiling with a
+        // compiler that supports rvalue references.  It basically turns
+        // an lvalue into an rvalue, allowing a move constructor to be
+        // called instead of a copy constructor (since we won't be using
+        // the return value any more), which is usually more efficient if
+        // it exists.  If it doesn't, it shouldn't do any harm.
         string new_str =
-          _return_type->prepare_return_expr(out, indent_level, "result");
+          _return_type->prepare_return_expr(out, indent_level, "MOVE(result)");
         return_expr = _return_type->get_return_expr(new_str);
 
       } else {
@@ -258,11 +266,11 @@ call_function(ostream &out, int indent_level, bool convert_result,
 //               comment.
 ////////////////////////////////////////////////////////////////////
 void FunctionRemap::
-write_orig_prototype(ostream &out, int indent_level, bool local) const {
+write_orig_prototype(ostream &out, int indent_level, bool local, int num_default_args) const {
   if (local) {
-    _cppfunc->output(out, indent_level, NULL, false, _num_default_parameters);
+    _cppfunc->output(out, indent_level, NULL, false, num_default_args);
   } else {
-    _cppfunc->output(out, indent_level, &parser, false, _num_default_parameters);
+    _cppfunc->output(out, indent_level, &parser, false, num_default_args);
   }
 }
 
@@ -287,7 +295,6 @@ make_wrapper_entry(FunctionIndex function_index) {
     iwrapper._comment = InterrogateBuilder::trim_blanks(_cppfunc->_leading_comment->_comment);
   }
 
-
   if (output_function_names) {
     // If we're keeping the function names, record that the wrapper is
     // callable.
@@ -356,7 +363,7 @@ make_wrapper_entry(FunctionIndex function_index) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: FunctionRemap::get_call_str
-//       Access: Private
+//       Access: Public
 //  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
@@ -412,7 +419,12 @@ get_call_str(const string &container, const vector_string &pexprs) const {
       } 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();
+        if (container == "local_this") {
+          // This isn't important, it just looks a bit prettier.
+          call << container << "->" << _cppfunc->get_local_name();
+        } else {
+          call << "(" << container << ")->" << _cppfunc->get_local_name();
+        }
 
       } else {
         call << _cppfunc->get_local_name(&parser);
@@ -426,14 +438,27 @@ get_call_str(const string &container, const vector_string &pexprs) const {
       separator = ", ";
     }
 
-    for (int pn = _first_true_parameter;
-         pn < (int)_parameters.size();
-         ++pn) {
+    int pn = _first_true_parameter;
+    int num_parameters = pexprs.size();
+
+    if (_type == T_item_assignment_operator) {
+      // The last parameter is the value to set.
+      --num_parameters;
+    }
+
+    for (pn = _first_true_parameter;
+         pn < num_parameters; ++pn) {
+      nassertd(pn < _parameters.size()) break;
       call << separator;
       _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
       separator = ", ";
     }
     call << ")";
+
+    if (_type == T_item_assignment_operator) {
+      call << " = ";
+      _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
+    }
   }
 
   return call.str();
@@ -497,6 +522,7 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
   }
 
   string fname = _cppfunc->get_simple_name();
+  CPPType *rtype = _ftype->_return_type->resolve_type(&parser, _cppscope);
 
   if (_cpptype != (CPPType *)NULL &&
       ((_cppfunc->_storage_class & CPPInstance::SC_static) == 0) &&
@@ -533,13 +559,22 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
         fname == "operator <<=" ||
         fname == "operator >>=") {
       _type = T_assignment_method;
+
+    } else if (fname == "operator []" && !_const_method && rtype != NULL) {
+       // Check if this is an item-assignment operator.
+      CPPReferenceType *reftype = rtype->as_reference_type();
+      if (reftype != NULL && reftype->_pointing_at->as_const_type() == NULL) {
+        // It returns a mutable reference.
+        _type = T_item_assignment_operator;
+      }
     }
   }
 
   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);
+    //CPPType *type = params[i]->_type->resolve_type(&parser, _cppscope);
+    CPPType *type = params[i]->_type;
     Parameter param;
     param._has_name = true;
     param._name = params[i]->get_simple_name();
@@ -557,10 +592,16 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     if (param._remap == (ParameterRemap *)NULL) {
       // If we can't handle one of the parameter types, we can't call
       // the function.
-      //nout << "Can't handle parameter " << i << " of method " << *_cppfunc << "\n";
-      return false;
+      if (fname == "__traverse__") {
+        // Hack to record this even though we can't wrap visitproc.
+        param._remap = new ParameterRemapUnchanged(type);
+      } else {
+        //nout << "Can't handle parameter " << i << " of method " << *_cppfunc << "\n";
+        return false;
+      }
+    } else {
+      param._remap->set_default_value(params[i]->_initializer);
     }
-    param._remap->set_default_value(params[i]->_initializer);
 
     if (!param._remap->is_valid()) {
       nout << "Invalid remap for parameter " << i << " of method " << *_cppfunc << "\n";
@@ -601,9 +642,39 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
       }
     }
 
+  } else if (_type == T_item_assignment_operator) {
+    // An item-assignment method isn't really a thing in C++, but it is
+    // in scripting languages, so we use this to denote item-access operators
+    // that return a non-const reference.
+
+    if (_cpptype == (CPPType *)NULL) {
+      nout << "Method " << *_cppfunc << " has no struct type\n";
+      return false;
+    } else {
+      // Synthesize a const reference parameter for the assignment.
+      CPPType *bare_type = TypeManager::unwrap_reference(rtype);
+      CPPType *const_type = CPPType::new_type(new CPPConstType(bare_type));
+      CPPType *ref_type = CPPType::new_type(new CPPReferenceType(const_type));
+
+      Parameter param;
+      param._has_name = true;
+      param._name = "assign_val";
+      param._remap = interface_maker->remap_parameter(_cpptype, ref_type);
+
+      if (param._remap == NULL || !param._remap->is_valid()) {
+        nout << "Invalid remap for assignment type of method " << *_cppfunc << "\n";
+        return false;
+      }
+      _parameters.push_back(param);
+
+      // Pretend we don't return anything at all.
+      CPPType *void_type = TypeManager::get_void_type();
+      _return_type = interface_maker->remap_parameter(_cpptype, void_type);
+      _void_return = true;
+    }
+
   } else {
     // The normal case.
-    CPPType *rtype = _ftype->_return_type->resolve_type(&parser, _cppscope);
     _return_type = interface_maker->remap_parameter(_cpptype, rtype);
     if (_return_type != (ParameterRemap *)NULL) {
       _void_return = TypeManager::is_void(rtype);
@@ -663,9 +734,10 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
     }
   }
 
-  if (_parameters.size() == first_param) {
+  if ((int)_parameters.size() == first_param) {
     _args_type = InterfaceMaker::AT_no_args;
-  } else if (_parameters.size() == first_param + 1) {
+  } else if ((int)_parameters.size() == first_param + 1 &&
+             _parameters[first_param]._remap->get_default_value() == NULL) {
     _args_type = InterfaceMaker::AT_single_arg;
   } else {
     _args_type = InterfaceMaker::AT_varargs;
@@ -682,8 +754,8 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
       }
 
     } else if (fname == "__setitem__") {
-      _flags |= F_setitem;
       if (_has_this && _parameters.size() > 2) {
+        _flags |= F_setitem;
         if (TypeManager::is_integer(_parameters[1]._remap->get_new_type())) {
           // Its first parameter is an int parameter, presumably an index.
           _flags |= F_setitem_int;
@@ -691,6 +763,16 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
         }
       }
 
+    } else if (fname == "__delitem__") {
+      if (_has_this && _parameters.size() == 2) {
+        _flags |= F_delitem;
+        if (TypeManager::is_integer(_parameters[1]._remap->get_new_type())) {
+          // Its first parameter is an int parameter, presumably an index.
+          _flags |= F_delitem_int;
+          _args_type = InterfaceMaker::AT_single_arg;
+        }
+      }
+
     } else if (fname == "size" || fname == "__len__") {
       if ((int)_parameters.size() == first_param &&
           TypeManager::is_integer(_return_type->get_new_type())) {
@@ -735,11 +817,20 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
         _flags |= F_compare_to;
       }
 
+    } else if (fname == "make") {
+      if (!_has_this && _parameters.size() >= 1 &&
+          TypeManager::is_pointer(_return_type->get_new_type())) {
+        // We can use this for coercion.
+        _flags |= F_coerce_constructor;
+      }
+
     } else if (fname == "operator ()" || fname == "__call__") {
       // Call operators always take keyword arguments.
       _args_type = InterfaceMaker::AT_keyword_args;
 
-    } else if (fname == "__setattr__" || fname == "__getattr__") {
+    } else if (fname == "__setattr__"
+            || fname == "__getattr__"
+            || fname == "__delattr__") {
       // Just to prevent these from getting keyword arguments.
 
     } else {
@@ -750,6 +841,19 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
       }
     }
 
+  } else if (_type == T_item_assignment_operator) {
+    // The concept of "item assignment operator" doesn't really exist in C++,
+    // but it does in scripting languages, and this allows us to wrap cases
+    // where the C++ getitem returns an assignable reference.
+    _flags |= F_setitem;
+    if (_has_this && _parameters.size() > 2) {
+      if (TypeManager::is_integer(_parameters[1]._remap->get_new_type())) {
+        // Its first parameter is an int parameter, presumably an index.
+        _flags |= F_setitem_int;
+      }
+    }
+    _args_type = InterfaceMaker::AT_varargs;
+
   } else if (_type == T_constructor) {
     if (!_has_this && _parameters.size() == 1 &&
         TypeManager::unwrap(_parameters[0]._remap->get_orig_type()) ==
@@ -758,7 +862,12 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
       // "this" type, this is a copy constructor.
       _flags |= F_copy_constructor;
 
+    } else if (!_has_this && _parameters.size() > 0 &&
+               (_cppfunc->_storage_class & CPPInstance::SC_explicit) == 0) {
+      // A non-explicit non-copy constructor might be eligible for coercion.
+      _flags |= F_coerce_constructor;
     }
+
     // Constructors always take varargs and keyword args.
     _args_type = InterfaceMaker::AT_keyword_args;
   }

+ 22 - 15
dtool/src/interrogate/functionRemap.h

@@ -52,14 +52,17 @@ public:
   ~FunctionRemap();
 
   string get_parameter_name(int n) const;
-  string call_function(ostream &out, int indent_level, 
+  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, bool local=false) const;
+  void write_orig_prototype(ostream &out, int indent_level, bool local=false,
+                            int num_default_args=0) const;
 
   FunctionWrapperIndex make_wrapper_entry(FunctionIndex function_index);
 
+  string get_call_str(const string &container, const vector_string &pexprs) const;
+
   class Parameter {
   public:
     bool _has_name;
@@ -76,21 +79,25 @@ public:
     T_typecast,
     T_getter,
     T_setter,
+    T_item_assignment_operator,
   };
 
   enum Flags {
-    F_getitem          = 0x0001,
-    F_getitem_int      = 0x0002,
-    F_size             = 0x0004,
-    F_setitem          = 0x0008,
-    F_setitem_int      = 0x0010,
-    F_make_copy        = 0x0020,
-    F_copy_constructor = 0x0040,
-    F_explicit_self    = 0x0080,
-    F_iter             = 0x0100,
-    F_getbuffer        = 0x0200,
-    F_releasebuffer    = 0x0400,
-    F_compare_to       = 0x0800,
+    F_getitem            = 0x0001,
+    F_getitem_int        = 0x0002,
+    F_size               = 0x0004,
+    F_setitem            = 0x0008,
+    F_setitem_int        = 0x0010,
+    F_delitem            = 0x0020,
+    F_delitem_int        = 0x0040,
+    F_make_copy          = 0x0080,
+    F_copy_constructor   = 0x0100,
+    F_explicit_self      = 0x0200,
+    F_iter               = 0x0400,
+    F_getbuffer          = 0x0800,
+    F_releasebuffer      = 0x1000,
+    F_compare_to         = 0x2000,
+    F_coerce_constructor = 0x4000,
   };
 
   typedef vector<Parameter> Parameters;
@@ -126,8 +133,8 @@ public:
   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_maker);
 };

+ 67 - 56
dtool/src/interrogate/interfaceMaker.cxx

@@ -41,7 +41,7 @@
 #include "pnotify.h"
 
 InterrogateType dummy_type;
- 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMaker::Function::Constructor
 //       Access: Public
@@ -59,7 +59,7 @@ Function(const string &name,
   _flags = 0;
   _args_type = AT_unknown;
 }
- 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMaker::Function::Destructor
 //       Access: Public
@@ -72,7 +72,7 @@ InterfaceMaker::Function::
     delete (*ri);
   }
 }
- 
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMaker::MakeSeq::Constructor
 //       Access: Public
@@ -141,9 +141,15 @@ check_protocols() {
   for (fi = _methods.begin(); fi != _methods.end(); ++fi) {
     Function *func = (*fi);
     flags |= func->_flags;
+
+    if (func->_ifunc.get_name() == "__traverse__") {
+      // If we have a method named __traverse__, we implement Python's
+      // cyclic garbage collection protocol.
+      _protocol_types |= PT_python_gc;
+    }
   }
 
-  if ((flags & (FunctionRemap::F_getitem_int | FunctionRemap::F_size)) == 
+  if ((flags & (FunctionRemap::F_getitem_int | FunctionRemap::F_size)) ==
       (FunctionRemap::F_getitem_int | FunctionRemap::F_size)) {
     // If we have both a getitem that receives an int, and a size,
     // then we implement the sequence protocol: you can iterate
@@ -169,8 +175,6 @@ check_protocols() {
     _protocol_types |= PT_iter;
   }
 
-  InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
-
   // Now are there any make_seq requests within this class?
   if (_itype._cpptype != NULL) {
     CPPStructType *stype = _itype._cpptype->as_struct_type();
@@ -269,18 +273,8 @@ generate_wrappers() {
   // traversal.
   int ti = 0;
   while (ti < idb->get_num_all_types()) {
-    TypeIndex type_index = idb->get_all_type(ti);
+    TypeIndex type_index = idb->get_all_type(ti++);
     record_object(type_index);
-
-    if (interrogate_type_is_enum(ti)) {
-      int enum_count = interrogate_type_number_of_enum_values(ti);
-      for (int xx = 0; xx < enum_count; ++xx) {
-//        printf("   PyModule_AddIntConstant(module,\"%s\",%d)\n",interrogate_type_enum_value_name(ti,xx),interrogate_type_enum_value(ti,xx));
-      }
-    }
-
-    ++ti;
-//    printf(" New Type %d\n",ti);
   }
 
   int num_global_elements = idb->get_num_global_elements();
@@ -321,7 +315,7 @@ generate_wrappers() {
       FunctionIndex func_index = ielement.get_setter();
       record_function(dummy_type, func_index);
     }
-  }    
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -396,7 +390,7 @@ remap_parameter(CPPType *struct_type, CPPType *param_type) {
     // convert basic_string<char>'s to atomic strings.
 
     if (struct_type == (CPPType *)NULL ||
-        !(TypeManager::is_basic_string_char(struct_type) || 
+        !(TypeManager::is_basic_string_char(struct_type) ||
           TypeManager::is_basic_string_wchar(struct_type))) {
       if (TypeManager::is_basic_string_char(param_type)) {
         return new ParameterRemapBasicStringToString(param_type);
@@ -454,7 +448,10 @@ remap_parameter(CPPType *struct_type, CPPType *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)) {
+  } else if (TypeManager::is_pointer(param_type) ||
+             TypeManager::is_void(param_type) ||
+             TypeManager::is_simple(param_type) ||
+             TypeManager::is_simple_array(param_type)) {
     return new ParameterRemapUnchanged(param_type);
 
   } else {
@@ -550,21 +547,19 @@ FunctionRemap *InterfaceMaker::
 make_function_remap(const InterrogateType &itype,
                     const InterrogateFunction &ifunc,
                     CPPInstance *cppfunc, int num_default_parameters) {
-  FunctionRemap *remap = 
+  FunctionRemap *remap =
     new FunctionRemap(itype, ifunc, cppfunc, num_default_parameters, this);
-  if (remap->_is_valid) 
-  {
-    if (separate_overloading()) 
-    {
+  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 = 
+      remap->_wrapper_name =
         get_wrapper_prefix() + _def->library_hash_name + remap->_hash;
       remap->_reported_name = remap->_wrapper_name;
-      if (true_wrapper_names) 
-      {
-        remap->_reported_name = 
+
+      if (true_wrapper_names) {
+        remap->_reported_name =
           InterrogateBuilder::clean_identifier(remap->_cppfunc->get_local_name(&parser));
       }
     }
@@ -589,7 +584,7 @@ make_function_remap(const InterrogateType &itype,
 //               an overloaded function) need not define a name here.
 ////////////////////////////////////////////////////////////////////
 string InterfaceMaker::
-get_wrapper_name(const InterrogateType &itype, 
+get_wrapper_name(const InterrogateType &itype,
                  const InterrogateFunction &ifunc,
                  FunctionIndex func_index) {
   string func_name = ifunc.get_scoped_name();
@@ -677,12 +672,13 @@ record_function(const InterrogateType &itype, FunctionIndex func_index) {
       // 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; 
+      for (int num_default_parameters = 0;
            num_default_parameters <= max_default_parameters;
            num_default_parameters++) {
-        FunctionRemap *remap = 
+        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"
@@ -741,7 +737,8 @@ record_object(TypeIndex type_index) {
   }
 
   InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
-  const InterrogateType &itype = idb->get_type(type_index);    
+  const InterrogateType &itype = idb->get_type(type_index);
+  assert(&itype != NULL);
 
   Object *object = new Object(itype);
   bool inserted = _objects.insert(Objects::value_type(type_index, object)).second;
@@ -754,29 +751,26 @@ record_object(TypeIndex type_index) {
     function = record_function(itype, itype.get_constructor(ci));
     object->_constructors.push_back(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)) 
-    {
+  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)) 
-    {
+    if (itype.derivation_has_downcast(di)) {
       // Downcasts are methods of the base class, not the child class.
       TypeIndex base_type_index = itype.get_derivation(di);
       const InterrogateType &base_type = idb->get_type(base_type_index);
@@ -785,27 +779,23 @@ record_object(TypeIndex type_index) {
   }
 
   int num_elements = itype.number_of_elements();
-  for (int ei = 0; ei < num_elements; ei++)
-  {
+  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()) 
-    {
+    if (ielement.has_getter()) {
       FunctionIndex func_index = ielement.get_getter();
       record_function(itype, func_index);
     }
-    if (ielement.has_setter()) 
-    {
+    if (ielement.has_setter()) {
       FunctionIndex func_index = ielement.get_setter();
       record_function(itype, func_index);
     }
-  }    
+  }
 
   object->check_protocols();
 
   int num_nested = itype.number_of_nested_types();
-  for (int ni = 0; ni < num_nested; ni++) 
-  {
+  for (int ni = 0; ni < num_nested; ni++) {
     TypeIndex nested_index = itype.get_nested_type(ni);
     record_object(nested_index);
   }
@@ -885,8 +875,14 @@ delete_return_value(ostream &out, int indent_level,
 //               the indicated variable name.
 ////////////////////////////////////////////////////////////////////
 void InterfaceMaker::
-output_ref(ostream &out, int indent_level, FunctionRemap *remap, 
+output_ref(ostream &out, int indent_level, FunctionRemap *remap,
            const string &varname) const {
+
+  if (TypeManager::is_pointer_to_base(remap->_return_type->get_temporary_type())) {
+    // Actually, we have it stored in a PointerTo.  No need to do anything.
+    return;
+  }
+
   if (remap->_type == FunctionRemap::T_constructor ||
       remap->_type == FunctionRemap::T_typecast) {
     // In either of these cases, we can safely assume the pointer will
@@ -915,8 +911,14 @@ output_ref(ostream &out, int indent_level, FunctionRemap *remap,
 //               the indicated variable name.
 ////////////////////////////////////////////////////////////////////
 void InterfaceMaker::
-output_unref(ostream &out, int indent_level, FunctionRemap *remap, 
+output_unref(ostream &out, int indent_level, FunctionRemap *remap,
              const string &varname) const {
+
+  if (TypeManager::is_pointer_to_base(remap->_return_type->get_temporary_type())) {
+    // Actually, we have it stored in a PointerTo.  No need to do anything.
+    return;
+  }
+
   if (remap->_type == FunctionRemap::T_constructor ||
       remap->_type == FunctionRemap::T_typecast) {
     // In either of these cases, we can safely assume the pointer will
@@ -931,8 +933,17 @@ output_unref(ostream &out, int indent_level, FunctionRemap *remap,
     indent(out, indent_level)
       << "if (" << varname << " != ("
       << remap->_return_type->get_new_type()->get_local_name(&parser) << ")NULL) {\n";
-    indent(out, indent_level + 2)
-      << "unref_delete(" << varname << ");\n";
+
+    if (TypeManager::is_pointer_to_base(remap->_return_type->get_temporary_type())) {
+      // We're sure the reference count won't reach zero since we have it
+      // stored in a PointerTo, so call the unref() method directly.
+      indent(out, indent_level + 2)
+        << varname << "->unref();\n";
+    } else {
+      indent(out, indent_level + 2)
+        << "unref_delete(" << varname << ");\n";
+    }
+
     indent(out, indent_level)
       << "}\n";
   }
@@ -967,7 +978,7 @@ hash_function_signature(FunctionRemap *remap) {
     nout << "Internal error!  Function signature "
          << remap->_function_signature << " repeated!\n";
     remap->_hash = hash;
-    abort(); 
+    abort();
     return;
   }
 

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

@@ -155,6 +155,7 @@ public:
       PT_make_copy        = 0x0004,
       PT_copy_constructor = 0x0008,
       PT_iter             = 0x0010,
+      PT_python_gc        = 0x0020,
     };
     int _protocol_types;
   };

文件差异内容过多而无法显示
+ 371 - 241
dtool/src/interrogate/interfaceMakerPythonNative.cxx


+ 90 - 41
dtool/src/interrogate/interfaceMakerPythonNative.h

@@ -31,32 +31,33 @@ class InterfaceMakerPythonNative : public InterfaceMakerPython {
 public:
   InterfaceMakerPythonNative(InterrogateModuleDef *def);
   virtual ~InterfaceMakerPythonNative();
-  
-  
+
+
   virtual void write_prototypes(ostream &out, ostream *out_h);
   void write_prototypes_class(ostream &out, ostream *out_h, Object *obj) ;
   void write_prototypes_class_external(ostream &out, Object *obj);
-  
+
   virtual void write_functions(ostream &out);
-  
+
   virtual void write_module(ostream &out, ostream *out_h, InterrogateModuleDef *def);
   virtual void write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def);
-  
-  void write_module_class(ostream &out, Object *cls); 
-  virtual void write_sub_module(ostream &out, Object *obj); 
-  
+
+  void write_module_class(ostream &out, Object *cls);
+  virtual void write_sub_module(ostream &out, Object *obj);
+
   virtual bool synthesize_this_parameter();
-  
+  virtual bool separate_overloading();
+
   virtual Object *record_object(TypeIndex type_index);
-  
+
 protected:
   virtual string get_wrapper_prefix();
   virtual string get_unique_prefix();
-  virtual void record_function_wrapper(InterrogateFunction &ifunc, 
+  virtual void record_function_wrapper(InterrogateFunction &ifunc,
                                        FunctionWrapperIndex wrapper_index);
-  
+
   virtual void generate_wrappers();
-  
+
 private:
   // This enum defines the various prototypes that must be generated
   // for the specialty functions that Python requires, especially for
@@ -65,7 +66,7 @@ private:
     WT_none,
     WT_no_params,
     WT_one_param,
-    WT_numeric_operator,
+    WT_binary_operator,
     WT_setattr,
     WT_getattr,
     WT_sequence_getitem,
@@ -76,8 +77,34 @@ private:
     WT_getbuffer,
     WT_releasebuffer,
     WT_iter_next,
-    WT_one_or_two_params,
     WT_ternary_operator,
+    WT_inplace_binary_operator,
+    WT_inplace_ternary_operator,
+    WT_traverse,
+  };
+
+  // This enum is passed to the wrapper generation functions to indicate
+  // what sort of values the wrapper function is expected to return.
+  enum ReturnFlags {
+    // -1 on failure, 0 on success.
+    RF_int  = 0x100,
+
+    // Returns the actual return value as PyObject*.
+    RF_pyobject = 0x010,
+
+    // Returns a reference to self.
+    RF_self = 0x020,
+
+    // Assign to the coerced argument, in the case of a coercion constructor.
+    RF_coerced = 0x040,
+
+    // These indicate what should be returned on error.
+    RF_err_notimplemented = 0x002,
+    RF_err_null = 0x004,
+    RF_err_false = 0x008,
+
+    // Decref temporary args object before returning.
+    RF_decref_args = 0x200,
   };
 
   class SlottedFunctionDef {
@@ -85,40 +112,59 @@ private:
     string _answer_location;
     WrapperType _wrapper_type;
     int _min_version;
+    Function *_func;
+    string _wrapper_name;
+    set<FunctionRemap*> _remaps;
   };
 
-  static bool get_slotted_function_def(Object *obj, Function *func, SlottedFunctionDef &def);
+  typedef std::map<string, SlottedFunctionDef> SlottedFunctions;
+
+  static bool get_slotted_function_def(Object *obj, Function *func, FunctionRemap *remap, SlottedFunctionDef &def);
+  static void write_function_slot(ostream &out, int indent_level,
+                                  const SlottedFunctions &slots,
+                                  const string &slot, const string &def = "0");
 
   void write_prototype_for_name(ostream &out, Function *func, const std::string &name);
   void write_prototype_for(ostream &out, Function *func);
   void write_function_for_top(ostream &out, Object *obj, Function *func);
-  void write_function_for_name(ostream &out, Object *obj, Function *func,
-                               const std::string &name,
-                               bool coercion_allowed, bool &coercion_attempted,
-                               ArgsType args_type, bool return_int, bool write_comment);
-
-  void write_function_forset(ostream &out, Object *obj, Function *func,
-                             std::set<FunctionRemap*> &remaps, string &expected_params,
-                             int indent_level, bool inplace,
-                             bool coercion_allowed, bool &coercion_attempted,
-                             ArgsType args_type, bool return_int,
+
+  void write_function_for_name(ostream &out, Object *obj,
+                               const Function::Remaps &remaps,
+                               const std::string &name, string &expected_params,
+                               bool coercion_allowed,
+                               ArgsType args_type, int return_flags);
+  void write_coerce_constructor(ostream &out, Object *obj, bool is_const);
+
+  int collapse_default_remaps(std::map<int, std::set<FunctionRemap *> > &map_sets,
+                              int max_required_args);
+
+  void write_function_forset(ostream &out,
+                             const std::set<FunctionRemap*> &remaps,
+                             int min_num_args, int max_num_args,
+                             string &expected_params, int indent_level,
+                             bool coercion_allowed, bool report_errors,
+                             ArgsType args_type, int return_flags,
+                             bool check_exceptions = true,
+                             bool verify_const = true,
                              const string &first_expr = string());
 
-  void write_function_instance(ostream &out, Object *obj, Function *func,
-                               FunctionRemap *remap, string &expected_params,
-                               int indent_level, bool is_inplace,
-                               bool coercion_allowed, bool &coercion_attempted,
-                               ArgsType args_type, bool return_int,
+  void write_function_instance(ostream &out, FunctionRemap *remap,
+                               int min_num_args, int max_num_args,
+                               string &expected_params, int indent_level,
+                               bool coercion_allowed, bool report_errors,
+                               ArgsType args_type, int return_flags,
+                               bool check_exceptions = true,
                                const string &first_pexpr = string());
 
+  void error_return(ostream &out, int indent_level, int return_flags);
+  void error_raise_return(ostream &out, int indent_level, int return_flags,
+                          const string &exc_type, const string &message,
+                          const string &format_args = "");
   void pack_return_value(ostream &out, int indent_level, FunctionRemap *remap,
-                         const std::string &return_expr, bool in_place);
-  void pack_python_value(ostream &out, int indent_level, FunctionRemap *remap,
-                         ParameterRemap *return_type, const std::string &return_expr,
-                         const std::string &assign_expr, bool in_place);
+                         std::string return_expr);
 
   void write_make_seq(ostream &out, Object *obj, const std::string &ClassName,
-                      MakeSeq *make_seq);
+                      const std::string &cClassName, MakeSeq *make_seq);
 
   void write_class_prototypes(ostream &out) ;
   void write_class_declarations(ostream &out, ostream *out_h, Object *obj);
@@ -126,7 +172,9 @@ private:
 
 public:
   bool is_remap_legal(FunctionRemap *remap);
-  bool is_function_legal( Function *func);
+  int has_coerce_constructor(CPPStructType *type);
+  bool is_remap_coercion_possible(FunctionRemap *remap);
+  bool is_function_legal(Function *func);
   bool is_cpp_type_legal(CPPType *ctype);
   bool isExportThisRun(CPPType *ctype);
   bool isExportThisRun(Function *func);
@@ -145,17 +193,18 @@ public:
   void get_valid_child_classes(std::map<std::string, CastDetails> &answer, CPPStructType *inclass, const std::string &upcast_seed = "", bool can_downcast = true);
   bool DoesInheritFromIsClass(const CPPStructType * inclass, const std::string &name);
   bool IsPandaTypedObject(CPPStructType * inclass) { return DoesInheritFromIsClass(inclass,"TypedObject"); };
-  void write_python_instance(ostream &out, int indent_level, const std::string &return_expr, const std::string &assign_expr, std::string &owns_memory_flag, const std::string &class_name, CPPType *ctype, bool inplace, const std::string &const_flag);
+  void write_python_instance(ostream &out, int indent_level, const std::string &return_expr, bool owns_memory, const std::string &class_name, CPPType *ctype, bool is_const);
   string HasAGetKeyFunction(const InterrogateType &itype_class);
   bool HasAGetClassTypeFunction(const InterrogateType &itype_class);
   int NeedsAStrFunction(const InterrogateType &itype_class);
   int NeedsAReprFunction(const InterrogateType &itype_class);
   bool NeedsARichCompareFunction(const InterrogateType &itype_class);
 
-  void output_quoted(ostream &out, int indent_level, const std::string &str);
-  
+  void output_quoted(ostream &out, int indent_level, const std::string &str,
+                     bool first_line=true);
+
   // stash the forward declarations for this compile pass..
-  std::set<std::string>     _external_imports;    
+  std::set<CPPType *> _external_imports;
 };
 
 #endif

+ 1 - 0
dtool/src/interrogate/interrogate.cxx

@@ -46,6 +46,7 @@ bool save_unique_names = false;
 bool no_database = false;
 bool generate_spam = false;
 bool left_inheritance_requires_upcast = true;
+bool mangle_names = true;
 CPPVisibility min_vis = V_published;
 string library_name;
 string module_name;

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

@@ -43,9 +43,9 @@ extern bool save_unique_names;
 extern bool no_database;
 extern bool generate_spam;
 extern bool left_inheritance_requires_upcast;
+extern bool mangle_names;
 extern CPPVisibility min_vis;
 extern string library_name;
 extern string module_name;
 
 #endif
-

+ 253 - 77
dtool/src/interrogate/interrogateBuilder.cxx

@@ -40,7 +40,7 @@
 #include "cppExtensionType.h"
 #include "cppStructType.h"
 #include "cppExpression.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppTypeDeclaration.h"
 #include "cppEnumType.h"
 #include "cppCommentBlock.h"
@@ -286,7 +286,8 @@ build() {
       }
 
     } else if ((*di)->get_subtype() == CPPDeclaration::ST_typedef) {
-      CPPTypedef *tdef = (*di)->as_typedef();
+      CPPTypedefType *tdef = (*di)->as_typedef_type();
+
       if (tdef->_type->get_subtype() == CPPDeclaration::ST_struct) {
         // A typedef counts as a declaration.  This lets us pick up
         // most template instantiations.
@@ -295,13 +296,16 @@ build() {
         scan_struct_type(struct_type);
       }
 
+      scan_typedef_type(tdef);
+
     } else if ((*di)->get_subtype() == CPPDeclaration::ST_type_declaration) {
       CPPType *type = (*di)->as_type_declaration()->_type;
+
       type->_vis = (*di)->_vis;
 
-      if (type->get_subtype() == CPPDeclaration::ST_struct)
-      {
-        CPPStructType *struct_type =type->as_type()->resolve_type(&parser, &parser)->as_struct_type();
+      if (type->get_subtype() == CPPDeclaration::ST_struct) {
+        CPPStructType *struct_type =
+          type->as_type()->resolve_type(&parser, &parser)->as_struct_type();
         scan_struct_type(struct_type);
 
       } else if (type->get_subtype() == CPPDeclaration::ST_enum) {
@@ -329,7 +333,8 @@ build() {
 //  Description: Generates all the code necessary to the indicated
 //               output stream.
 ////////////////////////////////////////////////////////////////////
-void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, InterrogateModuleDef *def) {
+void InterrogateBuilder::
+write_code(ostream &out_code,ostream * out_include, InterrogateModuleDef *def) {
   typedef vector<InterfaceMaker *> InterfaceMakers;
   InterfaceMakers makers;
 
@@ -394,9 +399,10 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
     }
     declaration_bodies << "#include \"py_panda.h\"\n";
     declaration_bodies << "#include \"extension.h\"\n";
+    declaration_bodies << "#include \"dcast.h\"\n";
   }
   declaration_bodies << "\n";
-  
+
   IncludeFiles::const_iterator ifi;
   for (ifi = _include_files.begin();
        ifi != _include_files.end();
@@ -413,7 +419,6 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
   }
   declaration_bodies << "\n";
 
-
   for (mi = makers.begin(); mi != makers.end(); ++mi) {
     (*mi)->write_includes(declaration_bodies);
   }
@@ -427,8 +432,6 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
 
   declaration_bodies << "\n";
 
-
-
   // And now the prototypes.
   for (mi = makers.begin(); mi != makers.end(); ++mi) {
     (*mi)->write_prototypes(declaration_bodies,out_include);
@@ -438,21 +441,19 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
 //  if(out_include != NULL)
 //    (*out_include) << declaration_bodies.str();
 //  else
-    out_code << declaration_bodies.str();
+  out_code << declaration_bodies.str();
 
-  
   // Followed by the function bodies.
   out_code << function_bodies.str() << "\n";
 
-    for (mi = makers.begin(); mi != makers.end(); ++mi) {
-      (*mi)->write_module_support(out_code,out_include,def);
-    }
-
+  for (mi = makers.begin(); mi != makers.end(); ++mi) {
+    (*mi)->write_module_support(out_code, out_include, def);
+  }
 
   if (output_module_specific) {
     // Output whatever stuff we should output if this were a module.
     for (mi = makers.begin(); mi != makers.end(); ++mi) {
-      (*mi)->write_module(out_code,out_include, def);
+      (*mi)->write_module(out_code, out_include, def);
     }
   }
 
@@ -461,7 +462,7 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
   for (mi = makers.begin(); mi != makers.end(); ++mi) {
     (*mi)->get_function_remaps(remaps);
   }
-  
+
   // Make sure all of the function wrappers appear first in the set of
   // indices, and that they occupy consecutive index numbers, so we
   // can build a simple array of function pointers by index.
@@ -504,7 +505,6 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
     out_code << "};\n\n";
   }
 
-
   if (save_unique_names) {
     // Write out the table of unique names, in no particular order.
     out_code << "static InterrogateUniqueNameDef _in_unique_names["
@@ -518,9 +518,6 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
     out_code << "};\n\n";
   }
 
-//if(1==2)
-{
-
   if (!no_database) {
     // Now build the module definition structure to add ourselves to
     // the global interrogate database.
@@ -544,7 +541,7 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
           << "  0,  /* num_unique_names */\n";
     }
 
-    if (output_function_pointers) { 
+    if (output_function_pointers) {
       out_code << "  _in_fptrs,\n"
           << "  " << num_wrappers << ",  /* num_fptrs */\n";
     } else {
@@ -565,7 +562,6 @@ void InterrogateBuilder::write_code(ostream &out_code,ostream * out_include, Int
         << "}\n\n";
   }
 }
-}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateBuilder::make_module_def
@@ -887,6 +883,15 @@ in_ignoreinvolved(CPPType *type) const {
       return false;
     }
 
+  case CPPDeclaration::ST_typedef:
+    {
+      if (in_ignoreinvolved(type->get_simple_name())) {
+        return true;
+      }
+      CPPTypedefType *tdef = type->as_typedef_type();
+      return in_ignoreinvolved(tdef->_type);
+    }
+
   default:
     return in_ignoreinvolved(type->get_simple_name());
   }
@@ -1145,7 +1150,7 @@ scan_function(CPPInstance *function) {
   }
 
   get_function(function, "",
-               (CPPStructType *)NULL, scope, 
+               (CPPStructType *)NULL, scope,
                InterrogateFunction::F_global);
 }
 
@@ -1181,8 +1186,7 @@ scan_struct_type(CPPStructType *type) {
 
   // Check if any of the members are exported.  If none of them are,
   // and the type itself is not marked for export, then never mind.
-  if (type->_vis > min_vis) 
-  {
+  if (type->_vis > min_vis) {
     CPPScope *scope = type->_scope;
 
     bool any_exported = false;
@@ -1192,6 +1196,7 @@ scan_struct_type(CPPStructType *type) {
          ++di) {
       if ((*di)->_vis <= min_vis) {
         any_exported = true;
+        break;
       }
     }
 
@@ -1241,6 +1246,93 @@ scan_enum_type(CPPEnumType *type) {
   get_type(type, true);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateBuilder::scan_typedef_type
+//       Access: Private
+//  Description: Adds the indicated typedef type to the database, if
+//               warranted.
+////////////////////////////////////////////////////////////////////
+void InterrogateBuilder::
+scan_typedef_type(CPPTypedefType *type) {
+  if (type == (CPPTypedefType *)NULL) {
+    return;
+  }
+
+  // A typedef cannot be a template declaration.
+  assert(!type->is_template());
+
+  if (type->_file.is_c_file()) {
+    // This type declaration appears in a .C file.  We can only export
+    // types defined in a .h file.
+    return;
+  }
+
+  if (type->_file._source != CPPFile::S_local ||
+      in_ignorefile(type->_file._filename_as_referenced)) {
+    // The type is defined in some other package or in an
+    // ignorable file.
+    return;
+  }
+
+  // Do we require explicitly placing BEGIN_PUBLISH/END_PUBLISH
+  // blocks around typedefs for them to be exported?  My thinking is
+  // that we shoudn't, for now, since we don't require it for structs
+  // either (we only require it to have published methods).
+  //if (type->_vis > min_vis) {
+  //  // The wrapped type is not marked to be exported.
+  //  return;
+  //}
+
+  // Find out what this typedef points to.
+  CPPType *wrapped_type = type->_type;
+  bool forced = in_forcetype(wrapped_type->get_local_name(&parser));
+
+  while (wrapped_type->get_subtype() == CPPDeclaration::ST_typedef) {
+    wrapped_type = wrapped_type->as_typedef_type()->_type;
+    forced = forced || in_forcetype(wrapped_type->get_local_name(&parser));
+  }
+
+  CPPStructType *struct_type = wrapped_type->as_struct_type();
+  if (struct_type == (CPPStructType *)NULL) {
+    // We only export typedefs to structs, for now.
+    return;
+  }
+
+  // Always export typedefs pointing to forced types.
+  if (!forced) {
+    if (wrapped_type->_file._source != CPPFile::S_local ||
+        in_ignorefile(wrapped_type->_file._filename_as_referenced)) {
+      // The wrapped type is defined in some other package or
+      // in an ignorable file.
+      return;
+    }
+
+    // Check if any of the wrapped type's members are published.
+    // If none of them are, and the wrapped type itself is not
+    // marked for export, then never mind.
+    if (struct_type->_vis > min_vis) {
+      CPPScope *scope = struct_type->_scope;
+
+      bool any_exported = false;
+      CPPScope::Declarations::const_iterator di;
+      for (di = scope->_declarations.begin();
+           di != scope->_declarations.end() && !any_exported;
+           ++di) {
+        if ((*di)->_vis <= min_vis) {
+          any_exported = true;
+          break;
+        }
+      }
+
+      if (!any_exported) {
+        return;
+      }
+    }
+  }
+
+  get_type(type, true);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateBuilder::scan_manifest
 //       Access: Private
@@ -1683,6 +1775,11 @@ get_function(CPPInstance *function, string description,
     return 0;
   }
 
+  TypeIndex class_index = 0;
+  if (struct_type != (CPPStructType *)NULL) {
+    class_index = get_type(struct_type, false);
+  }
+
   string function_name = TypeManager::get_function_name(function);
   string function_signature = TypeManager::get_function_signature(function);
 
@@ -1698,18 +1795,17 @@ get_function(CPPInstance *function, string description,
     _functions_by_name.find(function_name);
   if (tni != _functions_by_name.end()) {
     FunctionIndex index = (*tni).second;
+
     // It's already here, so update the flags.
     InterrogateFunction &ifunction =
       InterrogateDatabase::get_ptr()->update_function(index);
 
-    // Not 100% sure why, but there's a case where this happens,
-    // in a case where a typedef shadowed an actual type. ~rdb
     nassertr(&ifunction != NULL, 0);
 
     ifunction._flags |= flags;
 
     // Also, make sure this particular signature is defined.
-    pair<InterrogateFunction::Instances::iterator, bool> result = 
+    pair<InterrogateFunction::Instances::iterator, bool> result =
       ifunction._instances->insert(InterrogateFunction::Instances::value_type(function_signature, function));
 
     InterrogateFunction::Instances::iterator ii = result.first;
@@ -1764,7 +1860,7 @@ get_function(CPPInstance *function, string description,
   if (struct_type != (CPPStructType *)NULL) {
     // The function is a method.
     ifunction->_flags |= InterrogateFunction::F_method;
-    ifunction->_class = get_type(struct_type, false);
+    ifunction->_class = class_index;
   }
 
   if (ftype->_flags & CPPFunctionType::F_unary_op) {
@@ -1974,7 +2070,7 @@ get_type(CPPType *type, bool global) {
   if (true_name.empty()) {
     // Whoops, it's an anonymous type.  That's okay, because we'll
     // usually only encounter them once anyway, so let's go ahead and
-    // define it without checking in _types_by_name.
+    // define it without checking _types_by_name first.
 
   } else {
     TypesByName::const_iterator tni = _types_by_name.find(true_name);
@@ -2044,29 +2140,39 @@ get_type(CPPType *type, bool global) {
     }
   }
 
-  CPPExtensionType *ext_type = type->as_extension_type();
-  if (ext_type != (CPPExtensionType *)NULL) {
-    // If it's an extension type of some kind, it might be scoped.
+  CPPScope *scope = NULL;
+  // If it's an extension type or typedef, it might be scoped.
+  if (CPPTypedefType *td_type = type->as_typedef_type()) {
+    scope = td_type->_ident->get_scope(&parser, &parser);
+
+  } else if (CPPExtensionType *ext_type = type->as_extension_type()) {
     if (ext_type->_ident != (CPPIdentifier *)NULL) {
-      CPPScope *scope = ext_type->_ident->get_scope(&parser, &parser);
-      while (scope->as_template_scope() != (CPPTemplateScope *)NULL)
-      {
-        assert(scope->get_parent_scope() != scope);
-        scope = scope->get_parent_scope();
-        assert(scope != (CPPScope *)NULL);
-      }
-      itype._cppscope = scope;
+      scope = ext_type->_ident->get_scope(&parser, &parser);
 
-      if (scope != &parser) {
-        // We're scoped!
-        itype._scoped_name =
-          descope(scope->get_local_name(&parser) + "::" + itype._name);
-        CPPStructType *struct_type = scope->get_struct_type();
+    } else if (CPPEnumType *enum_type = ext_type->as_enum_type()) {
+      // Special case for anonymous enums.
+      scope = enum_type->_parent_scope;
+    }
 
-        if (struct_type != (CPPStructType *)NULL) {
-          itype._flags |= InterrogateType::F_nested;
-          itype._outer_class = get_type(struct_type, false);
-        }
+  }
+
+  if (scope != (CPPScope *)NULL) {
+    while (scope->as_template_scope() != (CPPTemplateScope *)NULL) {
+      assert(scope->get_parent_scope() != scope);
+      scope = scope->get_parent_scope();
+      assert(scope != (CPPScope *)NULL);
+    }
+    itype._cppscope = scope;
+
+    if (scope != &parser) {
+      // We're scoped!
+      itype._scoped_name =
+        descope(scope->get_local_name(&parser) + "::" + itype._name);
+      CPPStructType *struct_type = scope->get_struct_type();
+
+      if (struct_type != (CPPStructType *)NULL) {
+        itype._flags |= InterrogateType::F_nested;
+        itype._outer_class = get_type(struct_type, false);
       }
     }
   }
@@ -2092,8 +2198,15 @@ get_type(CPPType *type, bool global) {
     } else if (type->as_extension_type() != (CPPExtensionType *)NULL) {
       define_extension_type(itype, type->as_extension_type());
 
+    } else if (type->as_typedef_type() != (CPPTypedefType *)NULL) {
+      define_typedef_type(itype, type->as_typedef_type());
+
+    } else if (type->as_array_type() != (CPPArrayType *)NULL) {
+      define_array_type(itype, type->as_array_type());
+
     } else {
-      //      nout << "Attempt to define invalid type " << true_name << "\n";
+      nout << "Attempt to define invalid type " << *type
+           << " (subtype " << type->get_subtype() << ")\n";
 
       // Remove the type from the database.
       InterrogateDatabase::get_ptr()->remove_type(index);
@@ -2129,6 +2242,16 @@ define_atomic_type(InterrogateType &itype, CPPSimpleType *cpptype) {
     itype._atomic_token = AT_int;
     break;
 
+  case CPPSimpleType::T_char16_t:
+    itype._flags |= InterrogateType::F_unsigned;
+    itype._atomic_token = AT_int;
+    break;
+
+  case CPPSimpleType::T_char32_t:
+    itype._flags |= InterrogateType::F_unsigned;
+    itype._atomic_token = AT_int;
+    break;
+
   case CPPSimpleType::T_int:
     if ((cpptype->_flags & CPPSimpleType::F_longlong) != 0) {
       itype._atomic_token = AT_longlong;
@@ -2150,7 +2273,8 @@ define_atomic_type(InterrogateType &itype, CPPSimpleType *cpptype) {
     break;
 
   default:
-    nout << "Invalid CPPSimpleType: " << (int)cpptype->_type << "\n";
+    nout << "Type \"" << *cpptype << "\" has invalid CPPSimpleType: "
+         << (int)cpptype->_type << "\n";
     itype._atomic_token = AT_not_atomic;
   }
 
@@ -2204,7 +2328,7 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
                    TypeIndex type_index, bool forced) {
   if (cpptype->get_simple_name().empty()) {
     // If the type has no name, forget it.  We don't export anonymous
-    // types.
+    // structs.
     return;
   }
 
@@ -2265,23 +2389,25 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
 
   // A struct type should always be global.
   itype._flags |= InterrogateType::F_global;
-  
+
   CPPScope *scope = cpptype->_scope;
-  
+
   CPPStructType::Derivation::const_iterator bi;
   for (bi = cpptype->_derivation.begin();
        bi != cpptype->_derivation.end();
        ++bi) {
-    const CPPStructType::Base &base = (*bi);
-    if (base._vis <= V_public) 
-    {
 
+    const CPPStructType::Base &base = (*bi);
+    if (base._vis <= V_public) {
       CPPType *base_type = TypeManager::resolve_type(base._base, scope);
       TypeIndex base_index = get_type(base_type, true);
 
-      
       if (base_index == 0) {
-        nout << *cpptype << " reports a derivation from an invalid type.\n";
+        if (base_type != NULL) {
+          nout << *cpptype << " reports a derivation from invalid type " << *base_type << ".\n";
+        } else {
+          nout << *cpptype << " reports a derivation from an invalid type.\n";
+        }
 
       } else {
         InterrogateType::Derivation d;
@@ -2289,7 +2415,7 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
         d._base = base_index;
         d._upcast = 0;
         d._downcast = 0;
-        
+
         // Do we need to synthesize upcast and downcast functions?
         bool generate_casts = false;
 
@@ -2297,12 +2423,12 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
         if (base._is_virtual) {
           // We do in the presence of virtual inheritance.
           generate_casts = true;
-          
+
         } else if (bi != cpptype->_derivation.begin()) {
           // Or if we're not talking about the leftmost fork of multiple
           // inheritance.
           generate_casts = true;
-          
+
         } else if (cpptype->_derivation.size() != 1 &&
                    left_inheritance_requires_upcast) {
           // Or even if we are the leftmost fork of multiple
@@ -2318,13 +2444,11 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
           // pointer, while the parent class won't).
           generate_casts = true;
         }
-        
-        if (generate_casts) {
-        
 
+        if (generate_casts) {
           d._upcast = get_cast_function(base_type, cpptype, "upcast");
           d._flags |= InterrogateType::DF_upcast;
-          
+
           if (base._is_virtual) {
             // If this is a virtual inheritance, we can't write a
             // downcast.
@@ -2371,8 +2495,9 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
           CPPExtensionType *nested_type = type->as_extension_type();
           assert(nested_type != (CPPExtensionType *)NULL);
 
-          // Only try to export named types.
-          if (nested_type->_ident != (CPPIdentifier *)NULL) {
+          // For now, we don't allow anonymous structs.
+          if (nested_type->_ident != (CPPIdentifier *)NULL ||
+              nested_type->as_enum_type() != (CPPEnumType *)NULL) {
             TypeIndex nested_index = get_type(nested_type, false);
             itype._nested_types.push_back(nested_index);
           }
@@ -2382,11 +2507,31 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
       CPPType *type = (*di)->as_enum_type();
 
       // An anonymous enum type.
-      if ((*di)->_vis <= min_vis) {
+      if (type->_vis <= min_vis) {
         TypeIndex nested_index = get_type(type, false);
         itype._nested_types.push_back(nested_index);
       }
 
+    } else if ((*di)->get_subtype() == CPPDeclaration::ST_typedef) {
+      CPPTypedefType *type = (*di)->as_typedef_type();
+
+      // A nested typedef.  Unwrap it to find out what it's pointing to.
+      CPPType *wrapped_type = type->_type;
+
+      while (wrapped_type->get_subtype() == CPPDeclaration::ST_typedef) {
+        wrapped_type = wrapped_type->as_typedef_type()->_type;
+      }
+
+      CPPStructType *struct_type = wrapped_type->as_struct_type();
+      if (struct_type != (CPPStructType *)NULL) {
+        // We only export typedefs to structs, for now.
+
+        if (type->_vis <= min_vis) {
+          TypeIndex nested_index = get_type(type, false);
+          itype._nested_types.push_back(nested_index);
+        }
+      }
+
     } else if ((*di)->get_subtype() == CPPDeclaration::ST_make_property) {
       ElementIndex element_index = get_make_property((*di)->as_make_property(), cpptype);
       itype._elements.push_back(element_index);
@@ -2483,7 +2628,7 @@ update_function_comment(CPPInstance *function, CPPScope *scope) {
     ifunction._comment += comment;
 
     // Also update the particular wrapper comment.
-    InterrogateFunction::Instances::iterator ii = 
+    InterrogateFunction::Instances::iterator ii =
       ifunction._instances->find(function_signature);
     if (ii != ifunction._instances->end()) {
       if ((*ii).second->_leading_comment == NULL ||
@@ -2505,8 +2650,7 @@ void InterrogateBuilder::
 define_method(CPPFunctionGroup *fgroup, InterrogateType &itype,
               CPPStructType *struct_type, CPPScope *scope) {
   CPPFunctionGroup::Instances::const_iterator fi;
-  for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) 
-  {
+  for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
     CPPInstance *function = (*fi);
     define_method(function, itype, struct_type, scope);
   }
@@ -2642,7 +2786,7 @@ void InterrogateBuilder::
 define_enum_type(InterrogateType &itype, CPPEnumType *cpptype) {
   itype._flags |= InterrogateType::F_enum;
 
-  CPPScope *scope = &parser;
+  CPPScope *scope = cpptype->_parent_scope;
   if (cpptype->_ident != (CPPIdentifier *)NULL) {
     scope = cpptype->_ident->get_scope(&parser, &parser);
   }
@@ -2683,7 +2827,15 @@ define_enum_type(InterrogateType &itype, CPPEnumType *cpptype) {
 
     if (element->_initializer != (CPPExpression *)NULL) {
       CPPExpression::Result result = element->_initializer->evaluate();
-      next_value = result.as_integer();
+
+      if (result._type == CPPExpression::RT_error) {
+        nout << "enum value ";
+        element->output(nout, 0, &parser, true);
+        nout << " has invalid definition!\n";
+        return;
+      } else {
+        next_value = result.as_integer();
+      }
     }
     evalue._value = next_value;
     itype._enum_values.push_back(evalue);
@@ -2692,6 +2844,30 @@ define_enum_type(InterrogateType &itype, CPPEnumType *cpptype) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateBuilder::define_typedef_type
+//       Access: Private
+//  Description: Builds up a definition for the indicated typedef.
+////////////////////////////////////////////////////////////////////
+void InterrogateBuilder::
+define_typedef_type(InterrogateType &itype, CPPTypedefType *cpptype) {
+  itype._flags |= InterrogateType::F_typedef;
+  itype._wrapped_type = get_type(cpptype->_type, false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateBuilder::define_array_type
+//       Access: Private
+//  Description: Builds up a definition for the indicated wrapped type.
+////////////////////////////////////////////////////////////////////
+void InterrogateBuilder::
+define_array_type(InterrogateType &itype, CPPArrayType *cpptype) {
+  itype._flags |= InterrogateType::F_array;
+  itype._wrapped_type = get_type(cpptype->_element_type, false);
+
+  itype._array_size = cpptype->_bounds->evaluate().as_integer();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateBuilder::define_extension_type
 //       Access: Private

+ 5 - 0
dtool/src/interrogate/interrogateBuilder.h

@@ -33,6 +33,8 @@ class CPPConstType;
 class CPPExtensionType;
 class CPPStructType;
 class CPPEnumType;
+class CPPTypedefType;
+class CPPArrayType;
 class CPPFunctionType;
 class CPPScope;
 class CPPIdentifier;
@@ -92,6 +94,7 @@ public:
   void scan_function(CPPInstance *function);
   void scan_struct_type(CPPStructType *type);
   void scan_enum_type(CPPEnumType *type);
+  void scan_typedef_type(CPPTypedefType *type);
   void scan_manifest(CPPManifest *manifest);
   ElementIndex scan_element(CPPInstance *element, CPPStructType *struct_type,
                             CPPScope *scope);
@@ -128,6 +131,8 @@ public:
   void define_method(CPPInstance *function, InterrogateType &itype,
                      CPPStructType *struct_type, CPPScope *scope);
   void define_enum_type(InterrogateType &itype, CPPEnumType *cpptype);
+  void define_typedef_type(InterrogateType &itype, CPPTypedefType *cpptype);
+  void define_array_type(InterrogateType &itype, CPPArrayType *cpptype);
   void define_extension_type(InterrogateType &itype,
                              CPPExtensionType *cpptype);
 

+ 8 - 1
dtool/src/interrogate/parameterRemapConcreteToPointer.cxx

@@ -43,7 +43,14 @@ ParameterRemapConcreteToPointer(CPPType *orig_type) :
 ////////////////////////////////////////////////////////////////////
 void ParameterRemapConcreteToPointer::
 pass_parameter(ostream &out, const string &variable_name) {
-  out << "*" << variable_name;
+  if (variable_name.size() > 1 && variable_name[0] == '&') {
+    // Prevent generating something like *&param
+    // Also, if this is really some local type, we can presumably
+    // just move it?
+    out << "MOVE(" << variable_name.substr(1) << ")";
+  } else {
+    out << "*" << variable_name;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 10 - 1
dtool/src/interrogate/parameterRemapReferenceToPointer.cxx

@@ -42,7 +42,16 @@ ParameterRemapReferenceToPointer(CPPType *orig_type) :
 ////////////////////////////////////////////////////////////////////
 void ParameterRemapReferenceToPointer::
 pass_parameter(ostream &out, const string &variable_name) {
-  out << "*" << variable_name;
+  if (variable_name.size() > 1 && variable_name[0] == '&') {
+    // Prevent generating something like *&param
+    // Also, if this is really some local type, we can presumably just
+    // move it?  This is only relevant if this parameter is an rvalue
+    // reference, but CPPParser can't know that, and it might have an overload
+    // that takes an rvalue reference.  It shouldn't hurt either way.
+    out << "MOVE(" << variable_name.substr(1) << ")";
+  } else {
+    out << "*" << variable_name;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 9 - 9
dtool/src/interrogate/parse_file.cxx

@@ -16,7 +16,7 @@
 #include "cppManifest.h"
 #include "cppStructType.h"
 #include "cppFunctionGroup.h"
-#include "cppTypedef.h"
+#include "cppTypedefType.h"
 #include "cppExpressionParser.h"
 #include "cppExpression.h"
 #include "cppType.h"
@@ -166,7 +166,7 @@ show_data_members(const string &str) {
 }
 
 void
-show_typedefs(const string &str) {
+show_nested_types(const string &str) {
   CPPType *type = parser.parse_type(str);
   if (type == NULL) {
     cerr << "Invalid type: " << str << "\n";
@@ -182,12 +182,12 @@ show_typedefs(const string &str) {
   CPPScope *scope = stype->get_scope();
   assert(scope != (CPPScope *)NULL);
 
-  cerr << "Typedefs in " << *stype << ":\n";
+  cerr << "Nested types in " << *stype << ":\n";
 
-  CPPScope::Typedefs::const_iterator ti;
-  for (ti = scope->_typedefs.begin(); ti != scope->_typedefs.end(); ++ti) {
-    CPPTypedef *td = (*ti).second;
-    cerr << "  " << *td << "\n";
+  CPPScope::Types::const_iterator ti;
+  for (ti = scope->_types.begin(); ti != scope->_types.end(); ++ti) {
+    CPPType *tp = (*ti).second;
+    cerr << "  " << *tp << "\n";
   }
 }
 
@@ -286,8 +286,8 @@ main(int argc, char **argv) {
             show_methods(remainder);
           } else if (first_word == "members") {
             show_data_members(remainder);
-          } else if (first_word == "typedefs") {
-            show_typedefs(remainder);
+          } else if (first_word == "types") {
+            show_nested_types(remainder);
           } else {
             show_type_or_expression(str);
           }

文件差异内容过多而无法显示
+ 500 - 28
dtool/src/interrogate/typeManager.cxx


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

@@ -50,6 +50,7 @@ public:
   static bool is_ref_to_anything(CPPType *type);
   static bool is_const_ref_to_anything(CPPType *type);
   static bool is_const_pointer_to_anything(CPPType *type);
+  static bool is_const_pointer_or_ref(CPPType *type);
   static bool is_non_const_pointer_or_ref(CPPType *type);
   static bool is_pointer(CPPType *type);
   static bool is_const(CPPType *type);
@@ -61,9 +62,15 @@ public:
   static bool is_const_simple(CPPType *type);
   static bool is_const_ref_to_simple(CPPType *type);
   static bool is_ref_to_simple(CPPType *type);
+  static bool is_simple_array(CPPType *type);
+  static bool is_pointer_to_simple(CPPType *type);
   static bool is_pointable(CPPType *type);
   static bool is_char(CPPType *type);
+  static bool is_unsigned_char(CPPType *type);
   static bool is_char_pointer(CPPType *type);
+  static bool is_const_char_pointer(CPPType *type);
+  static bool is_unsigned_char_pointer(CPPType *type);
+  static bool is_const_unsigned_char_pointer(CPPType *type);
   static bool is_basic_string_char(CPPType *type);
   static bool is_const_basic_string_char(CPPType *type);
   static bool is_const_ref_to_basic_string_char(CPPType *type);
@@ -80,6 +87,8 @@ public:
   static bool is_bool(CPPType *type);
   static bool is_integer(CPPType *type);
   static bool is_unsigned_integer(CPPType *type);
+  static bool is_size(CPPType *type);
+  static bool is_ssize(CPPType *type);
   static bool is_short(CPPType *type);
   static bool is_unsigned_short(CPPType *type);
   static bool is_longlong(CPPType *type);
@@ -94,6 +103,8 @@ public:
   static bool is_const_ref_to_pointer_to_base(CPPType *type);
   static bool is_pointer_to_PyObject(CPPType *type);
   static bool is_PyObject(CPPType *type);
+  static bool is_pointer_to_PyTypeObject(CPPType *type);
+  static bool is_PyTypeObject(CPPType *type);
   static bool is_pointer_to_PyStringObject(CPPType *type);
   static bool is_PyStringObject(CPPType *type);
   static bool is_pointer_to_PyUnicodeObject(CPPType *type);
@@ -133,8 +144,8 @@ public:
   static bool has_protected_destructor(CPPType *type);
 
 
-  static bool IsExported(CPPType *type);
-  static bool IsLocal(CPPType *type);
+  static bool is_exported(CPPType *type);
+  static bool is_local(CPPType *type);
 
 };
 

+ 64 - 16
dtool/src/interrogatedb/dtool_super_base.cxx

@@ -15,7 +15,7 @@
 #include "py_panda.h"
 
 #ifdef HAVE_PYTHON
-  
+
 class EmptyClass {
 };
 Define_Module_Class_Private(dtoolconfig, DTOOL_SUPER_BASE, EmptyClass, DTOOL_SUPER_BASE111);
@@ -30,7 +30,7 @@ PyMethodDef Dtool_Methods_DTOOL_SUPER_BASE[] = {
   { NULL, NULL }
 };
 
-static Py_hash_t DTool_HashKey_Methods_DTOOL_SUPER_BASE(PyObject *self) {
+static Py_hash_t Dtool_HashKey_DTOOL_SUPER_BASE(PyObject *self) {
   void *local_this = DTOOL_Call_GetPointerThis(self);
   if (local_this == NULL) {
     return -1;
@@ -38,7 +38,7 @@ static Py_hash_t DTool_HashKey_Methods_DTOOL_SUPER_BASE(PyObject *self) {
   return (Py_hash_t) local_this;
 };
 
-inline void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module) {
+EXPCL_DTOOLCONFIG void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module) {
   static bool initdone = false;
   if (!initdone) {
 
@@ -46,15 +46,6 @@ inline void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module) {
     Dtool_DTOOL_SUPER_BASE.As_PyTypeObject().tp_dict = PyDict_New();
     PyDict_SetItemString(Dtool_DTOOL_SUPER_BASE.As_PyTypeObject().tp_dict, "DtoolClassDict", Dtool_DTOOL_SUPER_BASE.As_PyTypeObject().tp_dict);
 
-    // __hash__
-    Dtool_DTOOL_SUPER_BASE.As_PyTypeObject().tp_hash = &DTool_HashKey_Methods_DTOOL_SUPER_BASE;
-#if PY_MAJOR_VERSION >= 3
-    // Python 3 removed the regular tp_compare function - there is only tp_richcompare.
-    Dtool_DTOOL_SUPER_BASE.As_PyTypeObject().tp_richcompare = &DTOOL_PyObject_RichCompare;
-#else
-    Dtool_DTOOL_SUPER_BASE.As_PyTypeObject().tp_compare = &DTOOL_PyObject_Compare;
-#endif
-
     if (PyType_Ready(&Dtool_DTOOL_SUPER_BASE.As_PyTypeObject()) < 0) {
       PyErr_SetString(PyExc_TypeError, "PyType_Ready(Dtool_DTOOL_SUPER_BASE)");
       return;
@@ -83,9 +74,66 @@ int Dtool_Init_DTOOL_SUPER_BASE(PyObject *self, PyObject *args, PyObject *kwds)
   return -1;
 }
 
-int Dtool_InitNoCoerce_DTOOL_SUPER_BASE(PyObject *self, PyObject *args) {
-  PyErr_SetString(PyExc_TypeError, "cannot init super base");
-  return -1;
-}
+EXPORT_THIS Dtool_PyTypedObject Dtool_DTOOL_SUPER_BASE = {
+  {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "dtoolconfig.DTOOL_SUPER_BASE",
+    sizeof(Dtool_PyInstDef),
+    0,
+    &Dtool_FreeInstance_DTOOL_SUPER_BASE,
+    0,
+    0,
+    0,
+#if PY_MAJOR_VERSION >= 3
+    0,
+#else
+    &DTOOL_PyObject_Compare,
+#endif
+    0,
+    0,
+    0,
+    0,
+    &Dtool_HashKey_DTOOL_SUPER_BASE,
+    0,
+    0,
+    PyObject_GenericGetAttr,
+    PyObject_GenericSetAttr,
+    0,
+    (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES),
+    0,
+    0,
+    0,
+#if PY_MAJOR_VERSION >= 3
+    &DTOOL_PyObject_RichCompare,
+#else
+    0,
+#endif
+    0,
+    0,
+    0,
+    Dtool_Methods_DTOOL_SUPER_BASE,
+    standard_type_members,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    Dtool_Init_DTOOL_SUPER_BASE,
+    PyType_GenericAlloc,
+    Dtool_new_DTOOL_SUPER_BASE,
+    PyObject_Del,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+  },
+  Dtool_UpcastInterface_DTOOL_SUPER_BASE,
+  Dtool_DowncastInterface_DTOOL_SUPER_BASE,
+  TypeHandle::none(),
+};
 
 #endif  // HAVE_PYTHON

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

@@ -207,6 +207,16 @@ is_const() const {
   return (_flags & F_const) != 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateType::is_typedef
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool InterrogateType::
+is_typedef() const {
+  return (_flags & F_typedef) != 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateType::get_wrapped_type
 //       Access: Public
@@ -217,6 +227,26 @@ get_wrapped_type() const {
   return _wrapped_type;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateType::is_array
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool InterrogateType::
+is_array() const {
+  return (_flags & F_array) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateType::get_array_size
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE int InterrogateType::
+get_array_size() const {
+  return _array_size;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateType::is_enum
 //       Access: Public

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

@@ -32,6 +32,7 @@ InterrogateType(InterrogateModuleDef *def) :
   _outer_class = 0;
   _atomic_token = AT_not_atomic;
   _wrapped_type = 0;
+  _array_size = 1;
   _destructor = 0;
 
   _cpptype = (CPPType *)NULL;
@@ -111,6 +112,7 @@ operator = (const InterrogateType &copy) {
   _outer_class = copy._outer_class;
   _atomic_token = copy._atomic_token;
   _wrapped_type = copy._wrapped_type;
+  _array_size = copy._array_size;
   _constructors = copy._constructors;
   _destructor = copy._destructor;
   _elements = copy._elements;
@@ -165,6 +167,11 @@ output(ostream &out) const {
   out << _outer_class << " "
       << (int)_atomic_token << " "
       << _wrapped_type << " ";
+
+  if (is_array()) {
+    out << _array_size << " ";
+  }
+
   idf_output_vector(out, _constructors);
   out << _destructor << " ";
   idf_output_vector(out, _elements);
@@ -197,6 +204,10 @@ input(istream &in) {
   _atomic_token = (AtomicToken)token;
   in >> _wrapped_type;
 
+  if (is_array()) {
+    in >> _array_size;
+  }
+
   idf_input_vector(in, _constructors);
   in >> _destructor;
 

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

@@ -60,8 +60,12 @@ public:
   INLINE bool is_wrapped() const;
   INLINE bool is_pointer() const;
   INLINE bool is_const() const;
+  INLINE bool is_typedef() const;
   INLINE TypeIndex get_wrapped_type() const;
 
+  INLINE bool is_array() const;
+  INLINE int get_array_size() const;
+
   INLINE bool is_enum() const;
   INLINE int number_of_enum_values() const;
   INLINE const string &get_enum_value_name(int n) const;
@@ -132,6 +136,8 @@ private:
     F_nested               = 0x040000,
     F_enum                 = 0x080000,
     F_unpublished          = 0x100000,
+    F_typedef              = 0x200000,
+    F_array                = 0x400000,
   };
 
 public:
@@ -143,6 +149,7 @@ public:
   TypeIndex _outer_class;
   AtomicToken _atomic_token;
   TypeIndex _wrapped_type;
+  int _array_size;
 
   typedef vector<FunctionIndex> Functions;
   Functions _constructors;

+ 6 - 0
dtool/src/interrogatedb/interrogate_interface.cxx

@@ -613,6 +613,12 @@ interrogate_type_is_const(TypeIndex type) {
   return InterrogateDatabase::get_ptr()->get_type(type).is_const();
 }
 
+bool
+interrogate_type_is_typedef(TypeIndex type) {
+  //cerr << "interrogate_type_is_typedef(" << type << ")\n";
+  return InterrogateDatabase::get_ptr()->get_type(type).is_typedef();
+}
+
 TypeIndex
 interrogate_type_wrapped_type(TypeIndex type) {
   //cerr << "interrogate_type_wrapped_type(" << type << ")\n";

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

@@ -447,6 +447,7 @@ EXPCL_DTOOLCONFIG bool interrogate_type_is_short(TypeIndex type);
 EXPCL_DTOOLCONFIG bool interrogate_type_is_wrapped(TypeIndex type);
 EXPCL_DTOOLCONFIG bool interrogate_type_is_pointer(TypeIndex type);
 EXPCL_DTOOLCONFIG bool interrogate_type_is_const(TypeIndex type);
+EXPCL_DTOOLCONFIG bool interrogate_type_is_typedef(TypeIndex type);
 EXPCL_DTOOLCONFIG TypeIndex interrogate_type_wrapped_type(TypeIndex type);
 
 // If interrogate_type_is_enum() returns true, this is an enumerated

+ 259 - 232
dtool/src/interrogatedb/py_panda.cxx

@@ -18,19 +18,26 @@
 #ifdef HAVE_PYTHON
 
 PyMemberDef standard_type_members[] = {
-  {(char *)"this", T_ULONG, offsetof(Dtool_PyInstDef,_ptr_to_object),READONLY, (char *)"C++ 'this' pointer, if any"},
-//  {(char *)"this_ownership", T_INT, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"},
-//  {(char *)"this_const", T_INT, offsetof(Dtool_PyInstDef, _is_const), READONLY, (char *)"C++ 'this' const flag"},
+  {(char *)"this", (sizeof(void*) == sizeof(int)) ? T_UINT : T_ULONGLONG, offsetof(Dtool_PyInstDef, _ptr_to_object), READONLY, (char *)"C++ 'this' pointer, if any"},
+  {(char *)"this_ownership", T_BOOL, offsetof(Dtool_PyInstDef, _memory_rules), READONLY, (char *)"C++ 'this' ownership rules"},
+  {(char *)"this_const", T_BOOL, offsetof(Dtool_PyInstDef, _is_const), READONLY, (char *)"C++ 'this' const flag"},
 //  {(char *)"this_signature", T_INT, offsetof(Dtool_PyInstDef, _signature), READONLY, (char *)"A type check signature"},
   {(char *)"this_metatype", T_OBJECT, offsetof(Dtool_PyInstDef, _My_Type), READONLY, (char *)"The dtool meta object"},
   {NULL}  /* Sentinel */
 };
 
-////////////////////////////////////////////////////////////////////////
-/// Simple Recognition Functions..
-////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////
+//     Function: DtoolCanThisBeAPandaInstance
+//  Description: Given a valid (non-NULL) PyObject, does a simple
+//               check to see if it might be an instance of a Panda
+//               type.  It does this using a signature that is
+//               encoded on each instance.
+////////////////////////////////////////////////////////////////////
 bool DtoolCanThisBeAPandaInstance(PyObject *self) {
   // simple sanity check for the class type..size.. will stop basic foobars..
+  // It is arguably better to use something like this:
+  // PyType_IsSubtype(Py_TYPE(self), &Dtool_DTOOL_SUPER_BASE._PyType)
+  // ...but probably not as fast.
   if (Py_TYPE(self)->tp_basicsize >= (int)sizeof(Dtool_PyInstDef)) {
     Dtool_PyInstDef *pyself = (Dtool_PyInstDef *) self;
     if (pyself->_signature == PY_PANDA_SIGNATURE) {
@@ -56,101 +63,51 @@ void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject *c
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: attempt_coercion
-//  Description: A helper function for DTOOL_Call_GetPointerThisClass,
-//               below.  This attempts to coerce the given object to
-//               the indicated Panda object, by creating a temporary
-//               instance of the required Panda object.  If
-//               successful, returns the "this" pointer of the
-//               temporary object; otherwise, returns NULL.
-////////////////////////////////////////////////////////////////////
-static void *
-attempt_coercion(PyObject *self, Dtool_PyTypedObject *classdef,
-                 PyObject **coerced) {
-  // The supplied parameter is not the required type.
-  if (coerced != NULL) {
-    // Attempt coercion: try to create a temporary instance of the
-    // required class using the supplied parameter.
-    // Because we want to use the special InitNoCoerce constructor
-    // here instead of the regular constructor (we don't want to risk
-    // recursive coercion on the nested type we're creating), we have
-    // to call the constructor with a few more steps.
-    PyObject *obj = NULL;
-    if (classdef->_PyType.tp_new != NULL) {
-      obj = classdef->_PyType.tp_new(&classdef->_PyType, self, NULL);
-      assert(obj != NULL);
-
-      if (PyTuple_Check(self)) {
-        // A tuple was passed, which we assume are the constructor arguments.
-        if (classdef->_Dtool_InitNoCoerce(obj, self) != 0) {
-          Py_DECREF(obj);
-          obj = NULL;
-        }
-      } else {
-        // We need to pack the value into an args tuple.
-        PyObject *args = PyTuple_Pack(1, self);
-        if (classdef->_Dtool_InitNoCoerce(obj, args) != 0) {
-          Py_DECREF(obj);
-          obj = NULL;
-        }
-        Py_DECREF(args);
-      }
-    }
-    if (obj == NULL) {
-      // That didn't work; try to call a static "make" method instead.
-      // Presently, we don't bother filtering this for coercion,
-      // because none of our classes suffer from a recursion danger
-      // here.  Maybe one day we will need to also construct a
-      // makeNoCoerce wrapper?
-      PyObject *make = PyObject_GetAttrString((PyObject *)classdef, "make");
-      if (make != NULL) {
-        PyErr_Clear();
-        if (PyTuple_Check(self)) {
-          obj = PyObject_CallObject(make, self);
-        } else {
-          obj = PyObject_CallFunctionObjArgs(make, self, NULL);
-        }
-        Py_DECREF(make);
-      }
-    }
-    if (obj != NULL) {
-      // Well, whaddaya know?  The supplied parameter(s) suited
-      // the object's constructor.  Now we have a temporary object
-      // that we can pass to the function.
-      Dtool_PyTypedObject *my_type = ((Dtool_PyInstDef *)obj)->_My_Type;
-      void *result = my_type->_Dtool_UpcastInterface(obj, classdef);
-      if (result != NULL) {
-        // Successfully coerced.  Store the newly-allocated
-        // pointer, so the caller can release the coerced object
-        // at his leisure.  We store it in a list, so that other
-        // parameters can accumulate there too.
-        if ((*coerced) == NULL) {
-          (*coerced) = PyList_New(0);
-        }
-        PyList_Append(*coerced, obj);
-        Py_DECREF(obj);
-        return result;
-      }
-      // Some problem getting the C++ pointer from our created
-      // temporary object.  Weird.
-      Py_DECREF(obj);
-    }
-
-    // Clear the error returned by the coercion constructor.  It's not
-    // the error message we want to report.
-    PyErr_Clear();
+//     Function: Dtool_Call_ExtractThisPointer
+//  Description: This is a support function for the Python bindings:
+//               it extracts the underlying C++ pointer of the given
+//               type for a given Python object.  If it was of the
+//               wrong type, raises an AttributeError.
+////////////////////////////////////////////////////////////////////
+bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer) {
+  if (self == NULL || !DtoolCanThisBeAPandaInstance(self)) {
+    Dtool_Raise_TypeError("C++ object is not yet constructed, or already destructed.");
+    return false;
   }
-  return NULL;
+
+  *answer = ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self, &classdef);
+  return true;
 }
 
-// Temporary function to preserve backward compatibility.
-void *
-DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
-                               int param, const string &function_name, bool const_ok,
-                               PyObject **coerced) {
-  return DTOOL_Call_GetPointerThisClass(self, classdef,
-                                        param, function_name, const_ok,
-                                        coerced, true);
+////////////////////////////////////////////////////////////////////
+//     Function: Dtool_Call_ExtractThisPointer_NonConst
+//  Description: The same thing as Dtool_Call_ExtractThisPointer,
+//               except that it performs the additional check that
+//               the pointer is a non-const pointer.  This is called
+//               by function wrappers for functions of which all
+//               overloads are non-const, and saves a bit of code.
+//
+//               The extra method_name argument is used in formatting
+//               the error message.
+////////////////////////////////////////////////////////////////////
+bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef,
+                                            void **answer, const char *method_name) {
+
+  if (self == NULL || !DtoolCanThisBeAPandaInstance(self)) {
+    Dtool_Raise_TypeError("C++ object is not yet constructed, or already destructed.");
+    return false;
+  }
+
+  if (((Dtool_PyInstDef *)self)->_is_const) {
+    // All overloads of this function are non-const.
+    PyErr_Format(PyExc_TypeError,
+                 "Cannot call %s() on a const object.",
+                 method_name);
+    return false;
+  }
+
+  *answer = ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self, &classdef);
+  return true;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -176,18 +133,6 @@ DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
 //               declared non-const, and can therefore be called with
 //               only a non-const "this" pointer.
 //
-//               If coerced is non-NULL, parameter coercion will be
-//               attempted.  This means the supplied parameter may not
-//               exactly match the required type, but will satisfy the
-//               require type's constructor; and we will create
-//               temporary object(s) of the required type instead.  In
-//               this case, coerced is a pointer to a PyList that will
-//               be filled with these temporary objects.  If coerced
-//               is a pointer to a NULL PyObject, a new PyList will be
-//               created on the first successful coercion.  If coerced
-//               itself is NULL, parameter coercion will not be
-//               attempted.
-//
 //               The return value is the C++ pointer that was
 //               extracted, or NULL if there was a problem (in which
 //               case the Python exception state will have been set).
@@ -195,103 +140,36 @@ DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
 void *
 DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef,
                                int param, const string &function_name, bool const_ok,
-                               PyObject **coerced, bool report_errors) {
-  if (PyErr_Occurred()) {
+                               bool report_errors) {
+  //if (PyErr_Occurred()) {
+  //  return NULL;
+  //}
+  if (self == NULL) {
+    if (report_errors) {
+      return Dtool_Raise_TypeError("self is NULL");
+    }
     return NULL;
   }
-  if (self != NULL) {
-    if (DtoolCanThisBeAPandaInstance(self)) {
-      Dtool_PyTypedObject *my_type = ((Dtool_PyInstDef *)self)->_My_Type;
-      void *result = my_type->_Dtool_UpcastInterface(self, classdef);
-      if (result != NULL) {
-        if (const_ok || !((Dtool_PyInstDef *)self)->_is_const) {
-          return result;
-        }
-
-        if (report_errors) {
-          ostringstream str;
-          str << function_name << "() argument " << param << " may not be const";
-          string msg = str.str();
-          PyErr_SetString(PyExc_TypeError, msg.c_str());
-        }
-
-      } else {
-        if (report_errors) {
-          ostringstream str;
-          str << function_name << "() argument " << param << " must be ";
-
-          PyObject *fname = PyObject_GetAttrString((PyObject *)classdef, "__name__");
-          if (fname != (PyObject *)NULL) {
-#if PY_MAJOR_VERSION >= 3
-            str << PyUnicode_AsUTF8(fname);
-#else
-            str << PyString_AsString(fname);
-#endif
-            Py_DECREF(fname);
-          } else {
-            str << classdef->_name;
-          }
-
-          PyObject *tname = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "__name__");
-          if (tname != (PyObject *)NULL) {
-#if PY_MAJOR_VERSION >= 3
-            str << ", not " << PyUnicode_AsUTF8(tname);
-#else
-            str << ", not " << PyString_AsString(tname);
-#endif
-            Py_DECREF(tname);
-          } else {
-            str << ", not " << my_type->_name;
-          }
 
-          string msg = str.str();
-          PyErr_SetString(PyExc_TypeError, msg.c_str());
-        }
-      }
+  if (DtoolCanThisBeAPandaInstance(self)) {
+    void *result = ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self, classdef);
 
-    } else {
-      // The parameter was not a Panda type.  Can we coerce it to the
-      // appropriate type, by creating a temporary object?
-      void *result = attempt_coercion(self, classdef, coerced);
-      if (result != NULL) {
+    if (result != NULL) {
+      if (const_ok || !((Dtool_PyInstDef *)self)->_is_const) {
         return result;
       }
 
-      // Coercion failed.
       if (report_errors) {
-        ostringstream str;
-        str << function_name << "() argument " << param << " must be ";
-
-        PyObject *fname = PyObject_GetAttrString((PyObject *)classdef, "__name__");
-        if (fname != (PyObject *)NULL) {
-#if PY_MAJOR_VERSION >= 3
-          str << PyUnicode_AsUTF8(fname);
-#else
-          str << PyString_AsString(fname);
-#endif
-          Py_DECREF(fname);
-        } else {
-          str << classdef->_name;
-        }
-
-        PyObject *tname = PyObject_GetAttrString((PyObject *)Py_TYPE(self), "__name__");
-        if (tname != (PyObject *)NULL) {
-#if PY_MAJOR_VERSION >= 3
-          str << ", not " << PyUnicode_AsUTF8(tname);
-#else
-          str << ", not " << PyString_AsString(tname);
-#endif
-          Py_DECREF(tname);
-        }
-
-        string msg = str.str();
-        PyErr_SetString(PyExc_TypeError, msg.c_str());
+        return PyErr_Format(PyExc_TypeError,
+                            "%s() argument %d may not be const",
+                            function_name.c_str(), param);
       }
+      return NULL;
     }
-  } else {
-    if (report_errors) {
-      PyErr_SetString(PyExc_TypeError, "self is NULL");
-    }
+  }
+
+  if (report_errors) {
+    return Dtool_Raise_ArgTypeError(self, param, function_name.c_str(), classdef->_PyType.tp_name);
   }
 
   return NULL;
@@ -304,31 +182,175 @@ void *DTOOL_Call_GetPointerThis(PyObject *self) {
       return pyself->_ptr_to_object;
     }
   }
+  return NULL;
+}
+
+#ifndef NDEBUG
+////////////////////////////////////////////////////////////////////
+//     Function: Dtool_CheckErrorOccurred
+//  Description: This is similar to a PyErr_Occurred() check, except
+//               that it also checks Notify to see if an assertion
+//               has occurred.  If that is the case, then it raises
+//               an AssertionError.
+//
+//               Returns true if there is an active exception, false
+//               otherwise.
+//
+//               In the NDEBUG case, this is simply a #define to
+//               _PyErr_OCCURRED() (which is an undocumented inline
+//               version of PyErr_Occurred()).
+////////////////////////////////////////////////////////////////////
+bool Dtool_CheckErrorOccurred() {
+  if (_PyErr_OCCURRED()) {
+    return true;
+  }
+  if (Notify::ptr()->has_assert_failed()) {
+    Dtool_Raise_AssertionError();
+    return true;
+  }
+  return false;
+}
+#endif  // NDEBUG
+
+////////////////////////////////////////////////////////////////////
+//     Function: Dtool_Raise_AssertionError
+//  Description: Raises an AssertionError containing the last thrown
+//               assert message, and clears the assertion flag.
+//               Returns NULL.
+////////////////////////////////////////////////////////////////////
+PyObject *Dtool_Raise_AssertionError() {
+  Notify *notify = Notify::ptr();
+#if PY_MAJOR_VERSION >= 3
+  PyObject *message = PyUnicode_FromString(notify->get_assert_error_message().c_str());
+#else
+  PyObject *message = PyString_FromString(notify->get_assert_error_message().c_str());
+#endif
+  Py_INCREF(PyExc_AssertionError);
+  PyErr_Restore(PyExc_AssertionError, message, (PyObject *)NULL);
+  notify->clear_assert_failed();
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Dtool_Raise_TypeError
+//  Description: Raises a TypeError with the given message, and
+//               returns NULL.
+////////////////////////////////////////////////////////////////////
+PyObject *Dtool_Raise_TypeError(const char *message) {
+  // PyErr_Restore is what PyErr_SetString would have ended up calling
+  // eventually anyway, so we might as well just get to the point.
+  Py_INCREF(PyExc_TypeError);
+#if PY_MAJOR_VERSION >= 3
+  PyErr_Restore(PyExc_TypeError, PyUnicode_FromString(message), (PyObject *)NULL);
+#else
+  PyErr_Restore(PyExc_TypeError, PyString_FromString(message), (PyObject *)NULL);
+#endif
+  return NULL;
+}
 
+////////////////////////////////////////////////////////////////////
+//     Function: Dtool_Raise_ArgTypeError
+//  Description: Raises a TypeError of the form:
+//               function_name() argument n must be type, not type
+//               for a given object passed to a function.
+//
+//               Always returns NULL so that it can be conveniently
+//               used as a return expression for wrapper functions
+//               that return a PyObject pointer.
+////////////////////////////////////////////////////////////////////
+PyObject *Dtool_Raise_ArgTypeError(PyObject *obj, int param, const char *function_name, const char *type_name) {
+#if PY_MAJOR_VERSION >= 3
+  PyObject *message = PyUnicode_FromFormat(
+#else
+  PyObject *message = PyString_FromFormat(
+#endif
+    "%s() argument %d must be %s, not %s",
+    function_name, param, type_name,
+    Py_TYPE(obj)->tp_name);
+
+  Py_INCREF(PyExc_TypeError);
+  PyErr_Restore(PyExc_TypeError, message, (PyObject *)NULL);
   return NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Dtool_Raise_BadArgumentsError
+//  Description: Raises a TypeError of the form:
+//               Arguments must match:
+//               <list of overloads>
+//
+//               However, in release builds, this instead is defined
+//               to a function that just prints out a generic
+//               message, to help reduce the amount of strings in
+//               the compiled library.
+//
+//               Always returns NULL so that it can be conveniently
+//               used as a return expression for wrapper functions
+//               that return a PyObject pointer.
+////////////////////////////////////////////////////////////////////
+PyObject *_Dtool_Raise_BadArgumentsError() {
+  return Dtool_Raise_TypeError("arguments do not match any function overload");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Dtool_Return_None
+//  Description: Convenience method that checks for exceptions, and
+//               if one occurred, returns NULL, otherwise Py_None.
+////////////////////////////////////////////////////////////////////
+PyObject *_Dtool_Return_None() {
+  if (_PyErr_OCCURRED()) {
+    return NULL;
+  }
+#ifndef NDEBUG
+  if (Notify::ptr()->has_assert_failed()) {
+    return Dtool_Raise_AssertionError();
+  }
+#endif
+  Py_INCREF(Py_None);
+  return Py_None;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Dtool_Return_Bool
+//  Description: Convenience method that checks for exceptions, and
+//               if one occurred, returns NULL, otherwise the given
+//               boolean value as a PyObject *.
+////////////////////////////////////////////////////////////////////
+PyObject *Dtool_Return_Bool(bool value) {
+  if (_PyErr_OCCURRED()) {
+    return NULL;
+  }
+#ifndef NDEBUG
+  if (Notify::ptr()->has_assert_failed()) {
+    return Dtool_Raise_AssertionError();
+  }
+#endif
+  PyObject *result = (value ? Py_True : Py_False);
+  Py_INCREF(result);
+  return result;
+}
+
 ////////////////////////////////////////////////////////////////////////
 //  Function : DTool_CreatePyInstanceTyped
 //
 // this function relies on the behavior of typed objects in the panda system.
 //
 ////////////////////////////////////////////////////////////////////////
-PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject & known_class_type, bool memory_rules, bool is_const, int RunTimeType) {
-  if (local_this_in == NULL) {
-    // Let's not be stupid..
-    PyErr_SetString(PyExc_TypeError, "C Function Return Null 'this'");
-    return NULL;
-  }
+PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &known_class_type, bool memory_rules, bool is_const, int type_index) {
+  // We can't do the NULL check here like in DTool_CreatePyInstance, since
+  // the caller will have to get the type index to pass to this function
+  // to begin with.  That code probably would have crashed by now if it was
+  // really NULL for whatever reason.
+  nassertr(local_this_in != NULL, NULL);
 
   /////////////////////////////////////////////////////
   // IF the class is possibly a run time typed object
   /////////////////////////////////////////////////////
-  if (RunTimeType > 0) {
+  if (type_index > 0) {
     /////////////////////////////////////////////////////
     // get best fit class...
     /////////////////////////////////////////////////////
-    Dtool_PyTypedObject *target_class = Dtool_RuntimeTypeDtoolType(RunTimeType);
+    Dtool_PyTypedObject *target_class = Dtool_RuntimeTypeDtoolType(type_index);
     if (target_class != NULL) {
       /////////////////////////////////////////////////////
       // cast to the type...
@@ -343,7 +365,7 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
           self->_ptr_to_object = new_local_this;
           self->_memory_rules = memory_rules;
           self->_is_const = is_const;
-          self->_signature = PY_PANDA_SIGNATURE;
+          //self->_signature = PY_PANDA_SIGNATURE;
           self->_My_Type = target_class;
           return (PyObject *)self;
         }
@@ -360,7 +382,7 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
     self->_ptr_to_object = local_this_in;
     self->_memory_rules = memory_rules;
     self->_is_const = is_const;
-    self->_signature = PY_PANDA_SIGNATURE;
+    //self->_signature = PY_PANDA_SIGNATURE;
     self->_My_Type = &known_class_type;
   }
   return (PyObject *)self;
@@ -372,8 +394,10 @@ PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &
 ////////////////////////////////////////////////////////////////////////
 PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_classdef, bool memory_rules, bool is_const) {
   if (local_this == NULL) {
-    PyErr_SetString(PyExc_TypeError, "C Function Return Null 'this'");
-    return NULL;
+    // This is actually a very common case, so let's allow this, but return
+    // Py_None consistently.  This eliminates code in the wrappers.
+    Py_INCREF(Py_None);
+    return Py_None;
   }
 
   Dtool_PyTypedObject *classdef = &in_classdef;
@@ -425,7 +449,7 @@ void
 RegisterRuntimeClass(Dtool_PyTypedObject *otype, int class_id) {
   if (class_id == 0) {
     interrogatedb_cat.warning()
-      << "Class " << otype->_name
+      << "Class " << otype->_PyType.tp_name
       << " has a zero TypeHandle value; check that init_type() is called.\n";
 
   } else if (class_id > 0) {
@@ -436,13 +460,14 @@ RegisterRuntimeClass(Dtool_PyTypedObject *otype, int class_id) {
       // There was already an entry in the dictionary for class_id.
       Dtool_PyTypedObject *other_type = (*result.first).second;
       interrogatedb_cat.warning()
-        << "Classes " << otype->_name << " and " << other_type->_name
+        << "Classes " << otype->_PyType.tp_name
+        << " and " << other_type->_PyType.tp_name
         << " share the same TypeHandle value (" << class_id
         << "); check class definitions.\n";
 
     } else {
       GetRunTimeTypeList().insert(class_id);
-      otype->_Dtool_IsRunTimeCapable = true;
+      otype->_type = TypeRegistry::ptr()->find_type_by_id(class_id);
     }
   }
 }
@@ -495,11 +520,10 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
 
   if (module == NULL) {
 #if PY_MAJOR_VERSION >= 3
-    PyErr_SetString(PyExc_TypeError, "PyModule_Create returned NULL");
+    return Dtool_Raise_TypeError("PyModule_Create returned NULL");
 #else
-    PyErr_SetString(PyExc_TypeError, "Py_InitModule returned NULL");
+    return Dtool_Raise_TypeError("Py_InitModule returned NULL");
 #endif
-    return NULL;
   }
 
   // the constant inits... enums, classes ...
@@ -508,7 +532,6 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
   }
 
   PyModule_AddIntConstant(module, "Dtool_PyNativeInterface", 1);
-
   return module;
 }
 
@@ -523,20 +546,26 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) {
 PyObject *Dtool_BorrowThisReference(PyObject *self, PyObject *args) {
   PyObject *from_in = NULL;
   PyObject *to_in = NULL;
-  if (PyArg_ParseTuple(args, "OO", &to_in, &from_in)) {
+  if (PyArg_UnpackTuple(args, "Dtool_BorrowThisReference", 2, 2, &to_in, &from_in)) {
 
     if (DtoolCanThisBeAPandaInstance(from_in) && DtoolCanThisBeAPandaInstance(to_in)) {
-      Dtool_PyInstDef * from = (Dtool_PyInstDef *) from_in;
-      Dtool_PyInstDef * to = (Dtool_PyInstDef *) to_in;
+      Dtool_PyInstDef *from = (Dtool_PyInstDef *) from_in;
+      Dtool_PyInstDef *to = (Dtool_PyInstDef *) to_in;
+
+      //if (PyObject_TypeCheck(to_in, Py_TYPE(from_in))) {
       if (from->_My_Type == to->_My_Type) {
         to->_memory_rules = false;
         to->_is_const = from->_is_const;
         to->_ptr_to_object = from->_ptr_to_object;
-        return Py_BuildValue("");
+
+        Py_INCREF(Py_None);
+        return Py_None;
       }
-      PyErr_SetString(PyExc_TypeError, "Must Be Same Type??");
+
+      return PyErr_Format(PyExc_TypeError, "types %s and %s do not match",
+                          Py_TYPE(from)->tp_name, Py_TYPE(to)->tp_name);
     } else {
-      PyErr_SetString(PyExc_TypeError, "One of these does not appear to be DTOOL Instance ??");
+      return Dtool_Raise_TypeError("One of these does not appear to be DTOOL Instance ??");
     }
   }
   return (PyObject *) NULL;
@@ -551,16 +580,17 @@ PyObject *Dtool_AddToDictionary(PyObject *self1, PyObject *args) {
   PyObject *key;
   if (PyArg_ParseTuple(args, "OSO", &self, &key, &subject)) {
     PyObject *dict = ((PyTypeObject *)self)->tp_dict;
-    if (dict == NULL && !PyDict_Check(dict)) {
-      PyErr_SetString(PyExc_TypeError, "No dictionary On Object");
+    if (dict == NULL || !PyDict_Check(dict)) {
+      return Dtool_Raise_TypeError("No dictionary On Object");
     } else {
-      PyDict_SetItem(dict,key,subject);
+      PyDict_SetItem(dict, key, subject);
     }
   }
   if (PyErr_Occurred()) {
     return (PyObject *)NULL;
   }
-  return Py_BuildValue("");
+  Py_INCREF(Py_None);
+  return Py_None;
 }
 
 ///////////////////////////////////////////////////////////////////////////////////
@@ -725,7 +755,7 @@ PyObject *make_list_for_item(PyObject *self, const char *num_name,
       Py_DECREF(list);
       return NULL;
     }
-    PyList_SetItem(list, i, element);
+    PyList_SET_ITEM(list, i, element);
   }
   return list;
 }
@@ -772,18 +802,15 @@ PyObject *map_deepcopy_to_copy(PyObject *self, PyObject *args) {
 //               either a regular integer or a long integer, according
 //               to whether the indicated value will fit.
 ////////////////////////////////////////////////////////////////////
+#if PY_MAJOR_VERSION < 3
 EXPCL_DTOOLCONFIG PyObject *
 PyLongOrInt_FromUnsignedLong(unsigned long value) {
-#if PY_MAJOR_VERSION >= 3
-  // Python 3 only has longs.
-  return PyLong_FromUnsignedLong(value);
-#else
   if ((long)value < 0) {
     return PyLong_FromUnsignedLong(value);
   } else {
     return PyInt_FromLong((long)value);
   }
-#endif
 }
+#endif
 
 #endif  // HAVE_PYTHON

+ 200 - 178
dtool/src/interrogatedb/py_panda.h

@@ -13,12 +13,12 @@
 ////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////
 //  Too do list ..
-//      We need a better dispatcher for the functions..  The behavior today is 
-//          try one till it works or you run out of possibilities..  This is anything but optimal 
-//          for performance and is treading on thin ice for function python or c++ will 
+//      We need a better dispatcher for the functions..  The behavior today is
+//          try one till it works or you run out of possibilities..  This is anything but optimal
+//          for performance and is treading on thin ice for function python or c++ will
 //          course there types to other types.
 //
-//      The linking step will produce allot of warnings 
+//      The linking step will produce allot of warnings
 //                      warning LNK4049: locally defined symbol..
 //
 //  Get a second coder to review this file and the generated  code ..
@@ -40,6 +40,8 @@
 
 #endif
 
+#include "pnotify.h"
+
 #if defined(HAVE_PYTHON) && !defined(CPPPARSER)
 
 #ifdef _POSIX_C_SOURCE
@@ -102,21 +104,31 @@ inline PyObject* doPy_RETURN_FALSE()
 #define Py_TPFLAGS_CHECKTYPES 0
 #endif
 
-#if PY_MAJOR_VERSION < 3
-// For more portably defining hash functions.
-typedef long Py_hash_t;
-#endif
-
 #if PY_MAJOR_VERSION >= 3
+// For writing code that will compile in both versions.
 #define nb_nonzero nb_bool
 #define nb_divide nb_true_divide
 #define nb_inplace_divide nb_inplace_true_divide
+
+#define PyLongOrInt_Check(x) PyLong_Check(x)
+#define PyLongOrInt_FromSize_t PyLong_FromSize_t
+#define PyLongOrInt_FromLong PyLong_FromLong
+#define PyLongOrInt_FromUnsignedLong PyLong_FromUnsignedLong
+#define PyInt_Check PyLong_Check
+#define PyInt_AsLong PyLong_AsLong
+#define PyInt_AS_LONG PyLong_AS_LONG
+#else
+#define PyLongOrInt_Check(x) (PyInt_Check(x) || PyLong_Check(x))
+// PyInt_FromSize_t automatically picks the right type.
+#define PyLongOrInt_FromSize_t PyInt_FromSize_t
+#define PyLongOrInt_FromLong PyInt_FromLong
+
+// For more portably defining hash functions.
+typedef long Py_hash_t;
 #endif
 
 using namespace std;
 
-#define PY_PANDA_SMALLER_FOOTPRINT 1
-
 ///////////////////////////////////////////////////////////////////////////////////
 // this is tempory .. untill this is glued better into the panda build system
 ///////////////////////////////////////////////////////////////////////////////////
@@ -138,42 +150,39 @@ EXPCL_DTOOLCONFIG RunTimeTypeDictionary &GetRunTimeDictionary();
 EXPCL_DTOOLCONFIG RunTimeTypeList &GetRunTimeTypeList();
 
 //////////////////////////////////////////////////////////
-// used to stamp dtool instance.. 
+// used to stamp dtool instance..
 #define PY_PANDA_SIGNATURE 0xbeaf
-typedef void * ( * ConvertFunctionType  )(PyObject *,Dtool_PyTypedObject * );
-typedef void * ( * ConvertFunctionType1  )(void *, Dtool_PyTypedObject *);
-typedef void   ( *FreeFunction  )(PyObject *);
-typedef void   ( *PyModuleClassInit)(PyObject *module);
-typedef int    ( *InitNoCoerce)(PyObject *self, PyObject *args);
+typedef void *(*UpcastFunction)(PyObject *,Dtool_PyTypedObject *);
+typedef void *(*DowncastFunction)(void *, Dtool_PyTypedObject *);
 
 //inline          Dtool_PyTypedObject *  Dtool_RuntimeTypeDtoolType(int type);
-inline void     Dtool_Deallocate_General(PyObject * self);
+//inline void     Dtool_Deallocate_General(PyObject * self);
 //inline int      DTOOL_PyObject_Compare(PyObject *v1, PyObject *v2);
 //
 ////////////////////////////////////////////////////////////////////////
 // THIS IS THE INSTANCE CONTAINER FOR ALL panda py objects....
 ////////////////////////////////////////////////////////////////////////
-#ifdef  PY_PANDA_SMALLER_FOOTPRINT
-// this should save   8 bytes per object ....
 struct Dtool_PyInstDef {
   PyObject_HEAD
-  void *_ptr_to_object;
+
+  // This is a pointer to the Dtool_PyTypedObject type.  It's tempting
+  // not to store this and to instead use PY_TYPE(self) and upcast that,
+  // but that breaks when someone inherits from our class in Python.
   struct Dtool_PyTypedObject *_My_Type;
-  unsigned short _signature ; 
-  int _memory_rules : 1;   // true if we own the pointer and should delete it or unref it
-  int _is_const     : 1;       // true if this is a "const" pointer.
-};
 
-#else
-struct Dtool_PyInstDef {
-  PyObject_HEAD
+  // Pointer to the underlying C++ object.
   void *_ptr_to_object;
-  int _memory_rules;   // true if we own the pointer and should delete it or unref it
-  int _is_const;       // true if this is a "const" pointer.
-  unsigned long _signature;
-  struct Dtool_PyTypedObject *_My_Type;
+
+  // This is always set to PY_PANDA_SIGNATURE, so that we can quickly
+  // detect whether an object is a Panda object.
+  unsigned short _signature;
+
+  // True if we own the pointer and should delete it or unref it.
+  bool _memory_rules;
+
+  // True if this is a "const" pointer.
+  bool _is_const;
 };
-#endif
 
 ////////////////////////////////////////////////////////////////////////
 // A Offset Dictionary Defining How to read the Above Object..
@@ -188,144 +197,85 @@ struct Dtool_PyTypedObject {
   PyTypeObject _PyType;
 
   // My Class Level Features..
-  const char *_name;                             // cpp name for the object
-  bool _Dtool_IsRunTimeCapable;                  // derived from TypedObject
-  ConvertFunctionType _Dtool_UpcastInterface;    // The Upcast Function By Slot
-  ConvertFunctionType1 _Dtool_DowncastInterface; // The Downcast Function By Slot
-  FreeFunction _Dtool_FreeInstance;
-  PyModuleClassInit _Dtool_ClassInit;            // The module init function pointer
-  InitNoCoerce _Dtool_InitNoCoerce;              // A variant of the constructor that does not attempt to perform coercion of its arguments.
+  UpcastFunction _Dtool_UpcastInterface;    // The Upcast Function By Slot
+  DowncastFunction _Dtool_DowncastInterface; // The Downcast Function By Slot
+
+  // May be TypeHandle::none() to indicate a non-TypedObject class.
+  TypeHandle _type;
 
   // some convenience functions..
   inline PyTypeObject &As_PyTypeObject() { return _PyType; };
   inline PyObject &As_PyObject() { return (PyObject &)_PyType; };
 };
 
-////////////////////////////////////////////////////////////////////////
-// Macros from Hell..  May want to just add this to the code generator..
-////////////////////////////////////////////////////////////////////////
-#define Define_Dtool_PyTypedObject(MODULE_NAME, CLASS_NAME, PUBLIC_NAME) \
-  EXPORT_THIS Dtool_PyTypedObject Dtool_##CLASS_NAME =                  \
-    {                                                                   \
-      {                                                                 \
-        PyVarObject_HEAD_INIT(NULL, 0)                                  \
-        #MODULE_NAME "." #PUBLIC_NAME,       /*type name with module */ \
-        sizeof(Dtool_PyInstDef),                /* tp_basicsize */      \
-        0,                                      /* tp_itemsize */       \
-        &Dtool_Deallocate_General,              /* tp_dealloc */        \
-        0,                                      /* tp_print */          \
-        0,                                      /* tp_getattr */        \
-        0,                                      /* tp_setattr */        \
-        0,                                      /* tp_compare */        \
-        0,                                      /* tp_repr */           \
-        &Dtool_PyNumberMethods_##CLASS_NAME,    /* tp_as_number */      \
-        &Dtool_PySequenceMethods_##CLASS_NAME,  /* tp_as_sequence */    \
-        &Dtool_PyMappingMethods_##CLASS_NAME,   /* tp_as_mapping */     \
-        0,                                      /* tp_hash */           \
-        0,                                      /* tp_call */           \
-        0,                                      /* tp_str */            \
-        PyObject_GenericGetAttr,                /* tp_getattro */       \
-        PyObject_GenericSetAttr,                /* tp_setattro */       \
-        &Dtool_PyBufferProcs_##CLASS_NAME,      /* tp_as_buffer */      \
-        (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES), /* tp_flags */ \
-        0,                                      /* tp_doc */            \
-        0,                                      /* tp_traverse */       \
-        0,                                      /* tp_clear */          \
-        0,                                      /* tp_richcompare */    \
-        0,                                      /* tp_weaklistoffset */ \
-        0,                                      /* tp_iter */           \
-        0,                                      /* tp_iternext */       \
-        Dtool_Methods_##CLASS_NAME,             /* tp_methods */        \
-        standard_type_members,                  /* tp_members */        \
-        0,                                      /* tp_getset */         \
-        0,                                      /* tp_base */           \
-        0,                                      /* tp_dict */           \
-        0,                                      /* tp_descr_get */      \
-        0,                                      /* tp_descr_set */      \
-        0,                                      /* tp_dictoffset */     \
-        Dtool_Init_##CLASS_NAME,                /* tp_init */           \
-        PyType_GenericAlloc,                    /* tp_alloc */          \
-        Dtool_new_##CLASS_NAME,                 /* tp_new */            \
-        PyObject_Del,                           /* tp_free */           \
-      },                                                                \
-      #CLASS_NAME,                                                      \
-      false,                                                            \
-      Dtool_UpcastInterface_##CLASS_NAME,                               \
-      Dtool_DowncastInterface_##CLASS_NAME,                             \
-      Dtool_FreeInstance_##CLASS_NAME,                                  \
-      Dtool_PyModuleClassInit_##CLASS_NAME,                             \
-      Dtool_InitNoCoerce_##CLASS_NAME                                   \
-    };
-
-#define Define_Dtool_Class(MODULE_NAME, CLASS_NAME, PUBLIC_NAME)        \
-  static PyNumberMethods Dtool_PyNumberMethods_##CLASS_NAME = {0};      \
-  static PySequenceMethods Dtool_PySequenceMethods_##CLASS_NAME = {0};  \
-  static PyMappingMethods Dtool_PyMappingMethods_##CLASS_NAME = {0};    \
-  static PyBufferProcs Dtool_PyBufferProcs_##CLASS_NAME = {0};          \
-  Define_Dtool_PyTypedObject(MODULE_NAME, CLASS_NAME, PUBLIC_NAME)
-
-////////////////////////////////////////////////////////////////////////
-// The Fast Deallocator.. for Our instances..
-////////////////////////////////////////////////////////////////////////
-inline void Dtool_Deallocate_General(PyObject * self) {
-  ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_FreeInstance(self);
-  Py_TYPE(self)->tp_free(self);
-}
+// This is now simply a forward declaration.  The actual definition is created
+// by the code generator.
+#define Define_Dtool_Class(MODULE_NAME, CLASS_NAME, PUBLIC_NAME) \
+  extern Dtool_PyTypedObject Dtool_##CLASS_NAME;
 
 ////////////////////////////////////////////////////////////////////////
-//  More Macro(s) to Implement class functions.. Usually used if C++ needs type information 
+//  More Macro(s) to Implement class functions.. Usually used if C++ needs type information
 ////////////////////////////////////////////////////////////////////////
 #define Define_Dtool_new(CLASS_NAME,CNAME)\
-PyObject *Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds)\
-{\
-    PyObject *self = type->tp_alloc(type, 0);\
-    ((Dtool_PyInstDef *)self)->_signature = PY_PANDA_SIGNATURE;\
-    ((Dtool_PyInstDef *)self)->_ptr_to_object = NULL;\
-    ((Dtool_PyInstDef *)self)->_memory_rules = false;\
-    ((Dtool_PyInstDef *)self)->_is_const = false;\
-    ((Dtool_PyInstDef *)self)->_My_Type = &Dtool_##CLASS_NAME;\
-    return self;\
+PyObject *Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds) {\
+  (void) args; (void) kwds;\
+  PyObject *self = type->tp_alloc(type, 0);\
+  ((Dtool_PyInstDef *)self)->_signature = PY_PANDA_SIGNATURE;\
+  ((Dtool_PyInstDef *)self)->_My_Type = &Dtool_##CLASS_NAME;\
+  return self;\
 }
 
+// The following used to be in the above macro, but it doesn't seem to
+// be necessary as tp_alloc memsets the object to 0.
+  //((Dtool_PyInstDef *)self)->_ptr_to_object = NULL;\
+  //((Dtool_PyInstDef *)self)->_memory_rules = false;\
+  //((Dtool_PyInstDef *)self)->_is_const = false;\
+
 ////////////////////////////////////////////////////////////////////////
 /// Delete functions..
 ////////////////////////////////////////////////////////////////////////
 #ifdef NDEBUG
 #define Define_Dtool_FreeInstance_Private(CLASS_NAME,CNAME)\
-static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self)\
-{\
+static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
+  Py_TYPE(self)->tp_free(self);\
 }
 #else // NDEBUG
 #define Define_Dtool_FreeInstance_Private(CLASS_NAME,CNAME)\
-static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self)\
-{\
-    if(((Dtool_PyInstDef *)self)->_ptr_to_object != NULL)\
-        if(((Dtool_PyInstDef *)self)->_memory_rules)\
-        {\
-          cerr << "Detected leak for " << #CLASS_NAME \
-               << " which interrogate cannot delete.\n"; \
-        }\
+static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
+  if (((Dtool_PyInstDef *)self)->_ptr_to_object != NULL) {\
+    if (((Dtool_PyInstDef *)self)->_memory_rules) {\
+      cerr << "Detected leak for " << #CLASS_NAME \
+           << " which interrogate cannot delete.\n"; \
+    }\
+  }\
+  Py_TYPE(self)->tp_free(self);\
 }
 #endif  // NDEBUG
 
 #define Define_Dtool_FreeInstance(CLASS_NAME,CNAME)\
-static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self)\
-{\
-    if(((Dtool_PyInstDef *)self)->_ptr_to_object != NULL)\
-        if(((Dtool_PyInstDef *)self)->_memory_rules)\
-        {\
-            delete ((CNAME *)((Dtool_PyInstDef *)self)->_ptr_to_object);\
-        }\
+static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
+  if (((Dtool_PyInstDef *)self)->_ptr_to_object != NULL) {\
+    if (((Dtool_PyInstDef *)self)->_memory_rules) {\
+      delete ((CNAME *)((Dtool_PyInstDef *)self)->_ptr_to_object);\
+    }\
+  }\
+  Py_TYPE(self)->tp_free(self);\
 }
 
 #define Define_Dtool_FreeInstanceRef(CLASS_NAME,CNAME)\
-static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self)\
-{\
-    if(((Dtool_PyInstDef *)self)->_ptr_to_object != NULL)\
-        if(((Dtool_PyInstDef *)self)->_memory_rules)\
-        {\
-            unref_delete((CNAME *)((Dtool_PyInstDef *)self)->_ptr_to_object);\
-        }\
+static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
+  if (((Dtool_PyInstDef *)self)->_ptr_to_object != NULL) {\
+    if (((Dtool_PyInstDef *)self)->_memory_rules) {\
+      unref_delete((CNAME *)((Dtool_PyInstDef *)self)->_ptr_to_object);\
+    }\
+  }\
+  Py_TYPE(self)->tp_free(self);\
+}
+
+#define Define_Dtool_Simple_FreeInstance(CLASS_NAME, CNAME)\
+static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self) {\
+  ((Dtool_InstDef_##CLASS_NAME *)self)->_value.~##CLASS_NAME();\
+  Py_TYPE(self)->tp_free(self);\
 }
 
 ////////////////////////////////////////////////////////////////////////
@@ -333,38 +283,124 @@ static void Dtool_FreeInstance_##CLASS_NAME(PyObject *self)\
 ////////////////////////////////////////////////////////////////////////
 EXPCL_DTOOLCONFIG bool DtoolCanThisBeAPandaInstance(PyObject *self);
 
+///////////////////////////////////////////////////////////////////////////////
+//  ** HACK ** allert..
+//
+//      Need to keep a runtime type dictionary ... that is forward declared of typed object.
+//        We rely on the fact that typed objects are uniquly defined by an integer.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+EXPCL_DTOOLCONFIG void RegisterRuntimeClass(Dtool_PyTypedObject *otype, int class_id);
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+EXPCL_DTOOLCONFIG Dtool_PyTypedObject *Dtool_RuntimeTypeDtoolType(int type);
+
 ////////////////////////////////////////////////////////////////////////
 //  Function : DTOOL_Call_ExtractThisPointerForType
 //
-//  These are the wrappers that allow for down and upcast from type .. 
+//  These are the wrappers that allow for down and upcast from type ..
 //      needed by the Dtool py interface.. Be very careful if you muck
 //      with these as the generated code depends on how this is set
 //      up..
 ////////////////////////////////////////////////////////////////////////
 EXPCL_DTOOLCONFIG void DTOOL_Call_ExtractThisPointerForType(PyObject *self, Dtool_PyTypedObject * classdef, void ** answer);
 
-EXPCL_DTOOLCONFIG void *DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, int param, const string &function_name, bool const_ok, PyObject **coerced, bool report_errors);
-
-EXPCL_DTOOLCONFIG void *DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, int param, const string &function_name, bool const_ok, PyObject **coerced);
+EXPCL_DTOOLCONFIG void *DTOOL_Call_GetPointerThisClass(PyObject *self, Dtool_PyTypedObject *classdef, int param, const string &function_name, bool const_ok, bool report_errors);
 
 EXPCL_DTOOLCONFIG void *DTOOL_Call_GetPointerThis(PyObject *self);
 
+EXPCL_DTOOLCONFIG bool Dtool_Call_ExtractThisPointer(PyObject *self, Dtool_PyTypedObject &classdef, void **answer);
+
+EXPCL_DTOOLCONFIG bool Dtool_Call_ExtractThisPointer_NonConst(PyObject *self, Dtool_PyTypedObject &classdef,
+                                                              void **answer, const char *method_name);
+
+template<class T> INLINE bool DTOOL_Call_ExtractThisPointer(PyObject *self, T *&into) {
+  if (DtoolCanThisBeAPandaInstance(self)) {
+    Dtool_PyTypedObject *target_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
+    if (target_class != NULL) {
+      into = (T*) ((Dtool_PyInstDef *)self)->_My_Type->_Dtool_UpcastInterface(self, target_class);
+      return (into != NULL);
+    }
+  }
+  into = NULL;
+  return false;
+}
+
+// Functions related to error reporting.
+
+#ifdef NDEBUG
+// _PyErr_OCCURRED is an undocumented inline version of PyErr_Occurred.
+#define Dtool_CheckErrorOccurred() (_PyErr_OCCURRED() != NULL)
+#else
+EXPCL_DTOOLCONFIG bool Dtool_CheckErrorOccurred();
+#endif
+
+EXPCL_DTOOLCONFIG PyObject *Dtool_Raise_AssertionError();
+EXPCL_DTOOLCONFIG PyObject *Dtool_Raise_TypeError(const char *message);
+EXPCL_DTOOLCONFIG PyObject *Dtool_Raise_ArgTypeError(PyObject *obj, int param, const char *function_name, const char *type_name);
+
+EXPCL_DTOOLCONFIG PyObject *_Dtool_Raise_BadArgumentsError();
+#ifdef NDEBUG
+// Define it to a function that just prints a generic message.
+#define Dtool_Raise_BadArgumentsError(x) _Dtool_Raise_BadArgumentsError()
+#else
+// Expand this to a TypeError listing all of the overloads.
+#define Dtool_Raise_BadArgumentsError(x) Dtool_Raise_TypeError("Arguments must match:\n" x)
+#endif
+
+EXPCL_DTOOLCONFIG PyObject *_Dtool_Return_None();
+EXPCL_DTOOLCONFIG PyObject *Dtool_Return_Bool(bool value);
+
+#ifdef NDEBUG
+#define Dtool_Return_None() (_PyErr_OCCURRED() != NULL ? NULL : (Py_INCREF(Py_None), Py_None))
+#else
+#define Dtool_Return_None() _Dtool_Return_None()
+#endif
+
 ////////////////////////////////////////////////////////////////////////
 //  Function : DTool_CreatePyInstanceTyped
 //
-// this function relies on the behavior of typed objects in the panda system. 
+// this function relies on the behavior of typed objects in the panda system.
 //
 ////////////////////////////////////////////////////////////////////////
 EXPCL_DTOOLCONFIG PyObject *DTool_CreatePyInstanceTyped(void *local_this_in, Dtool_PyTypedObject &known_class_type, bool memory_rules, bool is_const, int RunTimeType);
 
 ////////////////////////////////////////////////////////////////////////
-// DTool_CreatePyInstance .. wrapper function to finalize the existance of a general 
+// DTool_CreatePyInstance .. wrapper function to finalize the existance of a general
 //    dtool py instance..
 ////////////////////////////////////////////////////////////////////////
 EXPCL_DTOOLCONFIG PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTypedObject &in_classdef, bool memory_rules, bool is_const);
 
+// These template methods allow use when the Dtool_PyTypedObject is not known.
+// They require a get_class_type() to be defined for the class.
+template<class T> INLINE PyObject *DTool_CreatePyInstance(const T *obj, bool memory_rules) {
+  Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
+  nassertr(known_class != NULL, NULL);
+  return DTool_CreatePyInstance((void*) obj, *known_class, memory_rules, true);
+}
+
+template<class T> INLINE PyObject *DTool_CreatePyInstance(T *obj, bool memory_rules) {
+  Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
+  nassertr(known_class != NULL, NULL);
+  return DTool_CreatePyInstance((void*) obj, *known_class, memory_rules, false);
+}
+
+template<class T> INLINE PyObject *DTool_CreatePyInstanceTyped(const T *obj, bool memory_rules) {
+  Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
+  nassertr(known_class != NULL, NULL);
+  return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, true, obj->get_type().get_index());
+}
+
+template<class T> INLINE PyObject *DTool_CreatePyInstanceTyped(T *obj, bool memory_rules) {
+  Dtool_PyTypedObject *known_class = Dtool_RuntimeTypeDtoolType(get_type_handle(T).get_index());
+  nassertr(known_class != NULL, NULL);
+  return DTool_CreatePyInstanceTyped((void*) obj, *known_class, memory_rules, false, obj->get_type().get_index());
+}
+
 ///////////////////////////////////////////////////////////////////////////////
-//  Macro(s) class definition .. Used to allocate storage and 
+//  Macro(s) class definition .. Used to allocate storage and
 //     init some values for a Dtool Py Type object.
 /////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////
@@ -372,13 +408,10 @@ EXPCL_DTOOLCONFIG PyObject *DTool_CreatePyInstance(void *local_this, Dtool_PyTyp
 
 #define Define_Module_Class_Internal(MODULE_NAME,CLASS_NAME,CNAME)\
 extern EXPORT_THIS   Dtool_PyTypedObject Dtool_##CLASS_NAME;\
-extern struct        PyMethodDef Dtool_Methods_##CLASS_NAME[];\
 int         Dtool_Init_##CLASS_NAME(PyObject *self, PyObject *args, PyObject *kwds);\
-int         Dtool_InitNoCoerce_##CLASS_NAME(PyObject *self, PyObject *args);\
 PyObject *  Dtool_new_##CLASS_NAME(PyTypeObject *type, PyObject *args, PyObject *kwds);\
 void  *     Dtool_UpcastInterface_##CLASS_NAME(PyObject *self, Dtool_PyTypedObject *requested_type);\
-void  *     Dtool_DowncastInterface_##CLASS_NAME(void *self, Dtool_PyTypedObject *requested_type);\
-void        Dtool_PyModuleClassInit_##CLASS_NAME(PyObject *module);
+void  *     Dtool_DowncastInterface_##CLASS_NAME(void *self, Dtool_PyTypedObject *requested_type);
 
 ///////////////////////////////////////////////////////////////////////////////
 #define Define_Module_Class(MODULE_NAME,CLASS_NAME,CNAME,PUBLIC_NAME)\
@@ -408,14 +441,13 @@ Define_Dtool_new(CLASS_NAME,CNAME)\
 Define_Dtool_FreeInstanceRef(CLASS_NAME,CNAME)\
 Define_Dtool_Class(MODULE_NAME,CLASS_NAME,PUBLIC_NAME)
 
-
 ///////////////////////////////////////////////////////////////////////////////
 /// Th Finalizer for simple instances..
 ///////////////////////////////////////////////////////////////////////////////
 EXPCL_DTOOLCONFIG int DTool_PyInit_Finalize(PyObject *self, void *This, Dtool_PyTypedObject *type, bool memory_rules, bool is_const);
 
 ///////////////////////////////////////////////////////////////////////////////
-/// A heler function to glu methed definition together .. that can not be done at 
+/// A heler function to glu methed definition together .. that can not be done at
 // code generation time becouse of multiple generation passes in interigate..
 //
 ///////////////////////////////////////////////////////////////////////////////
@@ -424,22 +456,8 @@ typedef std::map<std::string, PyMethodDef *> MethodDefmap;
 EXPCL_DTOOLCONFIG void Dtool_Accum_MethDefs(PyMethodDef in[], MethodDefmap &themap);
 
 ///////////////////////////////////////////////////////////////////////////////
-//  ** HACK ** allert..
-//
-//      Need to keep a runtime type dictionary ... that is forward declared of typed object.
-//        We rely on the fact that typed objects are uniquly defined by an integer.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-EXPCL_DTOOLCONFIG void RegisterRuntimeClass(Dtool_PyTypedObject * otype, int class_id);
-
-///////////////////////////////////////////////////////////////////////////////
-///////////////////////////////////////////////////////////////////////////////
-EXPCL_DTOOLCONFIG Dtool_PyTypedObject *Dtool_RuntimeTypeDtoolType(int type);
-
-///////////////////////////////////////////////////////////////////////////////
-//// We need a way to runtime merge compile units into a python "Module" .. this is done with the 
-/// fallowing structors and code.. along with the support of interigate_module 
+//// We need a way to runtime merge compile units into a python "Module" .. this is done with the
+/// fallowing structors and code.. along with the support of interigate_module
 ///////////////////////////////////////////////////////////////////////////////
 struct LibraryDef {
   typedef void (*ConstantFunction)(PyObject *);
@@ -456,7 +474,7 @@ EXPCL_DTOOLCONFIG PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const c
 #endif
 
 ///////////////////////////////////////////////////////////////////////////////
-///  HACK.... Be carefull 
+///  HACK.... Be carefull
 //
 //  Dtool_BorrowThisReference
 //      This function can be used to grab the "THIS" pointer from an object and use it
@@ -476,7 +494,7 @@ EXPCL_DTOOLCONFIG long  DTool_HashKey(PyObject * inst)
 {
     long   outcome = (long)inst;
     PyObject * func = PyObject_GetAttrString(inst, "__hash__");
-    if (func == NULL) 
+    if (func == NULL)
     {
         if(DtoolCanThisBeAPandaInstance(inst))
             if(((Dtool_PyInstDef *)inst)->_ptr_to_object != NULL)
@@ -488,13 +506,13 @@ EXPCL_DTOOLCONFIG long  DTool_HashKey(PyObject * inst)
         Py_DECREF(func);
         if (res == NULL)
             return -1;
-        if (PyInt_Check(res)) 
+        if (PyInt_Check(res))
         {
             outcome = PyInt_AsLong(res);
             if (outcome == -1)
                 outcome = -2;
         }
-        else 
+        else
         {
             PyErr_SetString(PyExc_TypeError,
                 "__hash__() should return an int");
@@ -531,11 +549,15 @@ copy_from_copy_constructor(PyObject *self);
 EXPCL_DTOOLCONFIG PyObject *
 map_deepcopy_to_copy(PyObject *self, PyObject *args);
 
+#if PY_MAJOR_VERSION < 3
+// In the Python 3 case, it is defined as a macro, at the beginning of this file.
 EXPCL_DTOOLCONFIG PyObject *
 PyLongOrInt_FromUnsignedLong(unsigned long value);
+#endif
 
 EXPCL_DTOOLCONFIG extern struct Dtool_PyTypedObject Dtool_DTOOL_SUPER_BASE;
+EXPCL_DTOOLCONFIG extern void Dtool_PyModuleClassInit_DTOOL_SUPER_BASE(PyObject *module);
 
 #endif  // HAVE_PYTHON && !CPPPARSER
 
-#endif // PY_PANDA_H_ 
+#endif // PY_PANDA_H_

+ 19 - 2
dtool/src/parser-inc/Python.h

@@ -26,14 +26,31 @@ typedef _object PyObject;
 struct _typeobject;
 typedef _typeobject PyTypeObject;
 
-struct PyStringObject;
-struct PyUnicodeObject;
+typedef struct {} PyStringObject;
+typedef struct {} PyUnicodeObject;
 
 class PyThreadState;
 typedef int Py_ssize_t;
 struct Py_buffer;
 
+// We need to define these accurately since interrogate may want to
+// write these out to default value assignments.
+PyObject _Py_NoneStruct;
+PyObject _Py_TrueStruct;
+#define Py_None (&_Py_NoneStruct)
+#define Py_True ((PyObject *) &_Py_TrueStruct)
+
+#if PY_MAJOR_VERSION >= 3
+PyObject _Py_ZeroStruct;
+#define Py_False ((PyObject *) &_Py_ZeroStruct)
+#else
+PyObject _Py_FalseStruct;
+#define Py_False ((PyObject *) &_Py_FalseStruct)
+#endif
+
 // This file defines PY_VERSION_HEX, which is used in some places.
 #include "patchlevel.h"
 
+typedef void *visitproc;
+
 #endif  // PYTHON_H

+ 7 - 6
dtool/src/parser-inc/cg.h

@@ -20,11 +20,12 @@
 #ifndef CG_H
 #define CG_H
 
-typedef int CGcontext;
-typedef int CGprogram;
-typedef int CGparameter;
-typedef int CGprofile;
-typedef int CGerror;
+typedef struct _CGcontext *CGcontext;
+typedef struct _CGcontext *CGcontext;
+typedef struct _CGprogram *CGprogram;
+typedef struct _CGparameter *CGparameter;
 
-#endif
+typedef enum {} CGprofile;
+typedef enum {} CGerror;
 
+#endif

+ 7 - 0
dtool/src/parser-inc/iostream

@@ -36,6 +36,13 @@ __published:
   };
   enum openmode {
   };
+  // Don't define these lest interrogate get tempted to actually
+  // substitute in the values, which are implementation-defined.
+  static const openmode app;
+  static const openmode binary;
+  static const openmode in;
+  static const openmode out;
+  static const openmode trunc;
 };
 class ios : public ios_base {
 __published:

+ 1 - 1
dtool/src/parser-inc/ssl.h

@@ -10,6 +10,6 @@ struct X509;
 struct X509_STORE;
 struct X509_NAME;
 struct SSL;
-#define STACK_OF(num) STACK
+#define STACK_OF(type) struct stack_st_##type
 
 #endif

+ 4 - 0
dtool/src/parser-inc/stdtypedefs.h

@@ -38,7 +38,11 @@ typedef unsigned long ulong;
 typedef unsigned short ushort;
 typedef unsigned char uchar;
 
+#ifdef __cplusplus
+#define NULL 0
+#else
 #define NULL ((void *)0)
+#endif
 
 typedef int fd_set;
 

+ 3 - 0
dtool/src/parser-inc/string

@@ -25,6 +25,9 @@
 template<class ctype>
 class basic_string {
 public:
+  typedef typename size_t size_type;
+  static const size_t npos;
+
   basic_string();
   basic_string(const basic_string &copy);
   void operator = (const basic_string &copy);

+ 3 - 3
dtool/src/parser-inc/windows.h

@@ -26,7 +26,7 @@ typedef long DWORD;
 typedef long LONG;
 typedef long UINT;
 typedef unsigned long ULONG;
-typedef signed __int64 LONGLONG;
+typedef signed long long LONGLONG;
 typedef long HRESULT;
 typedef int CRITICAL_SECTION;
 typedef int HANDLE;
@@ -45,12 +45,12 @@ typedef struct _STICKYKEYS STICKYKEYS;
 typedef struct _TOGGLEKEYS TOGGLEKEYS;
 typedef struct _FILTERKEYS FILTERKEYS;
 
-#define CALLBACK 
+#define CALLBACK
 
 #define WINAPI
 
 union LARGE_INTEGER {
-  __int64 QuadPart;
+  long long QuadPart;
 };
 
 class IGraphBuilder;

+ 2 - 10
dtool/src/parser-inc/winsock2.h

@@ -2,16 +2,8 @@
 #define _WINSOCK2API_
 #define _WINSOCKAPI_   /* Prevent inclusion of winsock.h in windows.h */
 
-typedef int SOCKET ;
+typedef int SOCKET;
 
-struct sockaddr_in
-{
-};
-
-
-typedef struct fd_set {
-        unsigned int fd_count;               /* how many are SET? */
-        SOCKET  fd_array[10];   /* an array of SOCKETs */
-} fd_set;
+struct sockaddr_in;
 
 #endif

+ 3 - 51
dtool/src/prc/notify.cxx

@@ -182,54 +182,6 @@ get_assert_handler() const {
   return _assert_handler;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: Notify::has_assert_failed
-//       Access: Public
-//  Description: Returns true if an assertion test has failed (and not
-//               been ignored) since the last call to
-//               clear_assert_failed().
-//
-//               When an assertion test fails, the assert handler
-//               may decide either to abort, return, or ignore the
-//               assertion.  Naturally, if it decides to abort, this
-//               flag is irrelevant.  If it chooses to ignore the
-//               assertion, the flag is not set.  However, if the
-//               assert handler chooses to return out of the
-//               function (the normal case), it will also set this
-//               flag to indicate that an assertion failure has
-//               occurred.
-//
-//               This will also be the behavior in the absence of a
-//               user-defined assert handler.
-////////////////////////////////////////////////////////////////////
-bool Notify::
-has_assert_failed() const {
-  return _assert_failed;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Notify::get_assert_error_message
-//       Access: Public
-//  Description: Returns the error message that corresponds to the
-//               assertion that most recently failed.
-////////////////////////////////////////////////////////////////////
-const string &Notify::
-get_assert_error_message() const {
-  return _assert_error_message;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Notify::clear_assert_failed
-//       Access: Public
-//  Description: Resets the assert_failed flag that is set whenever an
-//               assertion test fails.  See has_assert_failed().
-////////////////////////////////////////////////////////////////////
-void Notify::
-clear_assert_failed() {
-  _assert_failed = false;
-}
-
-
 ////////////////////////////////////////////////////////////////////
 //     Function: Notify::get_top_category
 //       Access: Public
@@ -269,7 +221,7 @@ get_category(const string &basename, NotifyCategory *parent_category) {
     }
   }
 
-  pair<Categories::iterator, bool> result = 
+  pair<Categories::iterator, bool> result =
     _categories.insert(Categories::value_type(fullname, (NotifyCategory *)NULL));
 
   bool inserted = result.second;
@@ -458,7 +410,7 @@ assert_failure(const char *expression, int line,
     // the debugger?  abort() doesn't do it.  We used to be able to
     // assert(false), but in VC++ 7 that just throws an exception, and
     // an uncaught exception just exits, without offering to open the
-    // debugger.  
+    // debugger.
 
     // DebugBreak() seems to be provided for this purpose, but it
     // doesn't seem to work properly either, since we don't seem to
@@ -567,7 +519,7 @@ config_initialized() {
           dup2(logfile_fd, STDOUT_FILENO);
           dup2(logfile_fd, STDERR_FILENO);
           close(logfile_fd);
-          
+
           set_ostream_ptr(&cerr, false);
         }
 #else

+ 47 - 0
dtool/src/prc/pnotify.I

@@ -12,3 +12,50 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: Notify::has_assert_failed
+//       Access: Public
+//  Description: Returns true if an assertion test has failed (and not
+//               been ignored) since the last call to
+//               clear_assert_failed().
+//
+//               When an assertion test fails, the assert handler
+//               may decide either to abort, return, or ignore the
+//               assertion.  Naturally, if it decides to abort, this
+//               flag is irrelevant.  If it chooses to ignore the
+//               assertion, the flag is not set.  However, if the
+//               assert handler chooses to return out of the
+//               function (the normal case), it will also set this
+//               flag to indicate that an assertion failure has
+//               occurred.
+//
+//               This will also be the behavior in the absence of a
+//               user-defined assert handler.
+////////////////////////////////////////////////////////////////////
+INLINE bool Notify::
+has_assert_failed() const {
+  return _assert_failed;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Notify::get_assert_error_message
+//       Access: Public
+//  Description: Returns the error message that corresponds to the
+//               assertion that most recently failed.
+////////////////////////////////////////////////////////////////////
+INLINE const string &Notify::
+get_assert_error_message() const {
+  return _assert_error_message;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Notify::clear_assert_failed
+//       Access: Public
+//  Description: Resets the assert_failed flag that is set whenever an
+//               assertion test fails.  See has_assert_failed().
+////////////////////////////////////////////////////////////////////
+INLINE void Notify::
+clear_assert_failed() {
+  _assert_failed = false;
+}

+ 3 - 3
dtool/src/prc/pnotify.h

@@ -51,9 +51,9 @@ PUBLISHED:
   bool has_assert_handler() const;
   AssertHandler *get_assert_handler() const;
 
-  bool has_assert_failed() const;
-  const string &get_assert_error_message() const;
-  void clear_assert_failed();
+  INLINE bool has_assert_failed() const;
+  INLINE const string &get_assert_error_message() const;
+  INLINE void clear_assert_failed();
 
   NotifyCategory *get_top_category();
   NotifyCategory *get_category(const string &basename,

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

@@ -79,6 +79,7 @@ extern "C" {
   EXPCL_PYSTUB int PyLong_AsUnsignedLongLong(...);
   EXPCL_PYSTUB int PyLong_FromLong(...);
   EXPCL_PYSTUB int PyLong_FromLongLong(...);
+  EXPCL_PYSTUB int PyLong_FromSize_t(...);
   EXPCL_PYSTUB int PyLong_FromUnsignedLong(...);
   EXPCL_PYSTUB int PyLong_FromUnsignedLongLong(...);
   EXPCL_PYSTUB int PyLong_Type(...);
@@ -122,6 +123,7 @@ extern "C" {
   EXPCL_PYSTUB int PySequence_Tuple(...);
   EXPCL_PYSTUB int PyString_AsString(...);
   EXPCL_PYSTUB int PyString_AsStringAndSize(...);
+  EXPCL_PYSTUB int PyString_FromFormat(...);
   EXPCL_PYSTUB int PyString_FromString(...);
   EXPCL_PYSTUB int PyString_FromStringAndSize(...);
   EXPCL_PYSTUB int PyString_InternFromString(...);
@@ -153,6 +155,8 @@ extern "C" {
   EXPCL_PYSTUB int PyUnicode_AsUTF8(...);
   EXPCL_PYSTUB int PyUnicode_AsUTF8AndSize(...);
   EXPCL_PYSTUB int PyUnicode_AsWideChar(...);
+  EXPCL_PYSTUB int PyUnicode_AsWideCharString(...);
+  EXPCL_PYSTUB int PyUnicode_FromFormat(...);
   EXPCL_PYSTUB int PyUnicode_FromString(...);
   EXPCL_PYSTUB int PyUnicode_FromStringAndSize(...);
   EXPCL_PYSTUB int PyUnicode_FromWideChar(...);
@@ -192,6 +196,7 @@ extern "C" {
   EXPCL_PYSTUB extern void *PyExc_SystemExit;
   EXPCL_PYSTUB extern void *PyExc_TypeError;
   EXPCL_PYSTUB extern void *PyExc_ValueError;
+  EXPCL_PYSTUB extern void *_PyThreadState_Current;
   EXPCL_PYSTUB extern void *_Py_FalseStruct;
   EXPCL_PYSTUB extern void *_Py_NoneStruct;
   EXPCL_PYSTUB extern void *_Py_NotImplementedStruct;
@@ -264,6 +269,7 @@ int PyLong_AsUnsignedLong(...) { return 0; }
 int PyLong_AsUnsignedLongLong(...) { return 0; }
 int PyLong_FromLong(...) { return 0; }
 int PyLong_FromLongLong(...) { return 0; }
+int PyLong_FromSize_t(...) { return 0; }
 int PyLong_FromUnsignedLong(...) { return 0; }
 int PyLong_FromUnsignedLongLong(...) { return 0; }
 int PyLong_Type(...) { return 0; }
@@ -307,6 +313,7 @@ int PySequence_Size(...) { return 0; }
 int PySequence_Tuple(...) { return 0; }
 int PyString_AsString(...) { return 0; }
 int PyString_AsStringAndSize(...) { return 0; }
+int PyString_FromFormat(...) { return 0; }
 int PyString_FromString(...) { return 0; }
 int PyString_FromStringAndSize(...) { return 0; }
 int PyString_InternFromString(...) { return 0; }
@@ -338,6 +345,8 @@ int PyUnicodeUCS4_GetSize(...) { return 0; }
 int PyUnicode_AsUTF8(...) { return 0; }
 int PyUnicode_AsUTF8AndSize(...) { return 0; }
 int PyUnicode_AsWideChar(...) { return 0; }
+int PyUnicode_AsWideCharString(...) { return 0; }
+int PyUnicode_FromFormat(...) { return 0; }
 int PyUnicode_FromString(...) { return 0; }
 int PyUnicode_FromStringAndSize(...) { return 0; }
 int PyUnicode_FromWideChar(...) { return 0; }
@@ -382,6 +391,7 @@ void *PyExc_StopIteration = (void *)NULL;
 void *PyExc_SystemExit = (void *)NULL;
 void *PyExc_TypeError = (void *)NULL;
 void *PyExc_ValueError = (void *)NULL;
+void *_PyThreadState_Current = (void *)NULL;
 void *_Py_FalseStruct = (void *)NULL;
 void *_Py_NoneStruct = (void *)NULL;
 void *_Py_NotImplementedStruct = (void *)NULL;

+ 1 - 1
makepanda/makepanda.py

@@ -1262,7 +1262,7 @@ def CompileIgate(woutd,wsrc,opts):
 
     cmd += ' -srcdir %s -I%s -Dvolatile -Dmutable' % (srcdir, srcdir)
     if (COMPILER=="MSVC"):
-        cmd += ' -DCPPPARSER -D__STDC__=1 -D__cplusplus -D__inline -longlong __int64 -D_X86_ -DWIN32_VC -DWIN32 -D_WIN32'
+        cmd += ' -DCPPPARSER -D__STDC__=1 -D__cplusplus -D__inline -D_X86_ -DWIN32_VC -DWIN32 -D_WIN32'
         if GetTargetArch() == 'x64':
             cmd += ' -DWIN64_VC -DWIN64 -D_WIN64'
         # NOTE: this 1600 value is the version number for VC2010.

+ 5 - 2
makepanda/makepandacore.py

@@ -2463,13 +2463,16 @@ def CopyPythonTree(dstdir, srcdir, lib2to3_fixers=[]):
             for fixer in lib2to3_fixers:
                 lib2to3_args += ['-f', fixer]
 
+    exclude_files = set(VCS_FILES)
+    exclude_files.add('panda3d.py')
+
     refactor = []
     for entry in os.listdir(srcdir):
         srcpth = os.path.join(srcdir, entry)
         dstpth = os.path.join(dstdir, entry)
-        if (os.path.isfile(srcpth)):
+        if os.path.isfile(srcpth):
             base, ext = os.path.splitext(entry)
-            if entry not in VCS_FILES and ext not in SUFFIX_INC + ['.pyc', '.pyo']:
+            if entry not in exclude_files and ext not in SUFFIX_INC + ['.pyc', '.pyo']:
                 if (NeedsBuild([dstpth], [srcpth])):
                     WriteBinaryFile(dstpth, ReadBinaryFile(srcpth))
 

+ 110 - 3
panda/src/display/graphicsWindowInputDevice.I

@@ -84,7 +84,7 @@ get_raw_pointer() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::set_device_index
 //       Access: Public
-//  Description: Set the device index.  This is reported in pointer 
+//  Description: Set the device index.  This is reported in pointer
 //               events.  The device index will be equal to the position
 //               of the GraphicsWindowInputDevice in the window's list.
 ////////////////////////////////////////////////////////////////////
@@ -117,9 +117,116 @@ disable_pointer_events() {
   _pointer_events.clear();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::button_down
+//       Access: Published
+//  Description: Records that the indicated button has been depressed.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindowInputDevice::
+button_down(ButtonHandle button) {
+  button_down(button, ClockObject::get_global_clock()->get_frame_time());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::button_resume_down
+//       Access: Published
+//  Description: Records that the indicated button was depressed
+//               earlier, and we only just detected the event after
+//               the fact.  This is mainly useful for tracking the
+//               state of modifier keys.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindowInputDevice::
+button_resume_down(ButtonHandle button) {
+  button_resume_down(button, ClockObject::get_global_clock()->get_frame_time());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::button_up
+//       Access: Published
+//  Description: Records that the indicated button has been released.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindowInputDevice::
+button_up(ButtonHandle button) {
+  button_up(button, ClockObject::get_global_clock()->get_frame_time());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::keystroke
+//       Access: Published
+//  Description: Records that the indicated keystroke has been
+//               generated.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindowInputDevice::
+keystroke(int keycode) {
+  keystroke(keycode, ClockObject::get_global_clock()->get_frame_time());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::focus_lost
+//       Access: Published
+//  Description: This should be called when the window focus is lost,
+//               so that we may miss upcoming button events
+//               (especially "up" events) for the next period of time.
+//               It generates keyboard and mouse "up" events for those
+//               buttons that we previously sent unpaired "down"
+//               events, so that the Panda application will believe
+//               all buttons are now released.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindowInputDevice::
+focus_lost() {
+  focus_lost(ClockObject::get_global_clock()->get_frame_time());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::raw_button_down
+//       Access: Published
+//  Description: Records that the indicated button has been depressed.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindowInputDevice::
+raw_button_down(ButtonHandle button) {
+  raw_button_down(button, ClockObject::get_global_clock()->get_frame_time());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::raw_button_up
+//       Access: Published
+//  Description: Records that the indicated button has been released.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindowInputDevice::
+raw_button_up(ButtonHandle button) {
+  raw_button_up(button, ClockObject::get_global_clock()->get_frame_time());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::set_pointer_in_window
-//       Access: Public
+//       Access: Published
+//  Description: To be called by a particular kind of GraphicsWindow
+//               to indicate that the pointer is within the window, at
+//               the given pixel coordinates.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindowInputDevice::
+set_pointer_in_window(double x, double y) {
+  // mutex is handled in set pointer .. convience function
+  set_pointer(true, x, y, ClockObject::get_global_clock()->get_frame_time());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::set_pointer_out_of_window
+//       Access: Published
+//  Description: To be called by a particular kind of GraphicsWindow
+//               to indicate that the pointer is no longer within the
+//               window.
+////////////////////////////////////////////////////////////////////
+INLINE void GraphicsWindowInputDevice::
+set_pointer_out_of_window() {
+ // mutex is handled in set pointer .. convience function
+  set_pointer(false, _mouse_data._xpos, _mouse_data._ypos,
+              ClockObject::get_global_clock()->get_frame_time());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsWindowInputDevice::set_pointer_in_window
+//       Access: Published
 //  Description: To be called by a particular kind of GraphicsWindow
 //               to indicate that the pointer is within the window, at
 //               the given pixel coordinates.
@@ -132,7 +239,7 @@ set_pointer_in_window(double x, double y, double time) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::set_pointer_out_of_window
-//       Access: Public
+//       Access: Published
 //  Description: To be called by a particular kind of GraphicsWindow
 //               to indicate that the pointer is no longer within the
 //               window.

+ 16 - 17
panda/src/display/graphicsWindowInputDevice.cxx

@@ -94,7 +94,7 @@ pointer_and_keyboard(GraphicsWindow *host, const string &name) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 GraphicsWindowInputDevice::
-GraphicsWindowInputDevice(const GraphicsWindowInputDevice &copy) 
+GraphicsWindowInputDevice(const GraphicsWindowInputDevice &copy)
 {
     *this = copy;
 }
@@ -105,7 +105,7 @@ GraphicsWindowInputDevice(const GraphicsWindowInputDevice &copy)
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindowInputDevice::
-operator = (const GraphicsWindowInputDevice &copy) 
+operator = (const GraphicsWindowInputDevice &copy)
 {
   LightMutexHolder holder(_lock);
   LightMutexHolder holder1(copy._lock);
@@ -165,7 +165,7 @@ get_button_event() {
 //     Function: GraphicsWindowInputDevice::has_pointer_event
 //       Access: Public
 //  Description: Returns true if this device has a pending pointer
-//               event (a mouse movement), or false otherwise.  If 
+//               event (a mouse movement), or false otherwise.  If
 //               this returns true, the particular event may be
 //               extracted via get_pointer_event().
 ////////////////////////////////////////////////////////////////////
@@ -234,7 +234,7 @@ disable_pointer_mode() {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::set_pointer
-//       Access: Public
+//       Access: Published
 //  Description: Records that a mouse movement has taken place.
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindowInputDevice::
@@ -264,7 +264,7 @@ set_pointer(bool inwin, double x, double y, double time) {
   } else {
     _mouse_data = _true_mouse_data;
   }
-  
+
   if (_enable_pointer_events) {
     int seq = _event_sequence++;
     if (_pointer_events == 0) {
@@ -279,7 +279,7 @@ set_pointer(bool inwin, double x, double y, double time) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::button_down
-//       Access: Public
+//       Access: Published
 //  Description: Records that the indicated button has been depressed.
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindowInputDevice::
@@ -291,7 +291,7 @@ button_down(ButtonHandle button, double time) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::button_resume_down
-//       Access: Public
+//       Access: Published
 //  Description: Records that the indicated button was depressed
 //               earlier, and we only just detected the event after
 //               the fact.  This is mainly useful for tracking the
@@ -300,14 +300,13 @@ button_down(ButtonHandle button, double time) {
 void GraphicsWindowInputDevice::
 button_resume_down(ButtonHandle button, double time) {
   LightMutexHolder holder(_lock);
-  _button_events.push_back(ButtonEvent(button, ButtonEvent::T_resume_down, time)
-);
+  _button_events.push_back(ButtonEvent(button, ButtonEvent::T_resume_down, time));
   _buttons_held.insert(button);
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::button_up
-//       Access: Public
+//       Access: Published
 //  Description: Records that the indicated button has been released.
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindowInputDevice::
@@ -319,7 +318,7 @@ button_up(ButtonHandle button, double time) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::keystroke
-//       Access: Public
+//       Access: Published
 //  Description: Records that the indicated keystroke has been
 //               generated.
 ////////////////////////////////////////////////////////////////////
@@ -331,24 +330,24 @@ keystroke(int keycode, double time) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::candidate
-//       Access: Public
+//       Access: Published
 //  Description: Records that the indicated candidate string has been
 //               highlighted.  This is used to implement IME support
 //               for typing in international languages, especially
 //               Chinese/Japanese/Korean.
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindowInputDevice::
-candidate(const wstring &candidate_string, size_t highlight_start, 
+candidate(const wstring &candidate_string, size_t highlight_start,
           size_t highlight_end, size_t cursor_pos) {
   LightMutexHolder holder(_lock);
-  _button_events.push_back(ButtonEvent(candidate_string, 
+  _button_events.push_back(ButtonEvent(candidate_string,
                                        highlight_start, highlight_end,
                                        cursor_pos));
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::focus_lost
-//       Access: Public
+//       Access: Published
 //  Description: This should be called when the window focus is lost,
 //               so that we may miss upcoming button events
 //               (especially "up" events) for the next period of time.
@@ -369,7 +368,7 @@ focus_lost(double time) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::raw_button_down
-//       Access: Public
+//       Access: Published
 //  Description: Records that the indicated button has been depressed.
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindowInputDevice::
@@ -380,7 +379,7 @@ raw_button_down(ButtonHandle button, double time) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsWindowInputDevice::raw_button_up
-//       Access: Public
+//       Access: Published
 //  Description: Records that the indicated button has been released.
 ////////////////////////////////////////////////////////////////////
 void GraphicsWindowInputDevice::

+ 20 - 10
panda/src/display/graphicsWindowInputDevice.h

@@ -76,18 +76,28 @@ public:
 PUBLISHED:
   // The following interface is for the various kinds of
   // GraphicsWindows to record the data incoming on the device.
-  void button_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
-  void button_resume_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
-  void button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
-  void keystroke(int keycode, double time = ClockObject::get_global_clock()->get_frame_time());
-  void candidate(const wstring &candidate_string, size_t highlight_start, 
+  INLINE void button_down(ButtonHandle button);
+  INLINE void button_resume_down(ButtonHandle button);
+  INLINE void button_up(ButtonHandle button);
+  INLINE void keystroke(int keycode);
+  INLINE void focus_lost();
+  INLINE void raw_button_down(ButtonHandle button);
+  INLINE void raw_button_up(ButtonHandle button);
+  INLINE void set_pointer_in_window(double x, double y);
+  INLINE void set_pointer_out_of_window();
+
+  void button_down(ButtonHandle button, double time);
+  void button_resume_down(ButtonHandle button, double time);
+  void button_up(ButtonHandle button, double time);
+  void keystroke(int keycode, double time);
+  void candidate(const wstring &candidate_string, size_t highlight_start,
                  size_t highlight_end, size_t cursor_pos);
-  void focus_lost(double time = ClockObject::get_global_clock()->get_frame_time());
-  void raw_button_down(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
-  void raw_button_up(ButtonHandle button, double time = ClockObject::get_global_clock()->get_frame_time());
+  void focus_lost(double time);
+  void raw_button_down(ButtonHandle button, double time);
+  void raw_button_up(ButtonHandle button, double time);
 
-  INLINE void set_pointer_in_window(double x, double y, double time = ClockObject::get_global_clock()->get_frame_time());
-  INLINE void set_pointer_out_of_window(double time = ClockObject::get_global_clock()->get_frame_time());
+  INLINE void set_pointer_in_window(double x, double y, double time);
+  INLINE void set_pointer_out_of_window(double time);
   void set_pointer(bool inwin, double x, double y, double time);
 
 public:

+ 2 - 2
panda/src/distort/nonlinearImager.cxx

@@ -183,7 +183,7 @@ get_num_screens() const {
 ////////////////////////////////////////////////////////////////////
 NodePath NonlinearImager::
 get_screen(int index) const {
-  nassertr(index >= 0 && index < (int)_screens.size(), (ProjectionScreen *)NULL);
+  nassertr(index >= 0 && index < (int)_screens.size(), NodePath());
   return _screens[index]._screen;
 }
 
@@ -215,7 +215,7 @@ get_buffer(int index) const {
 void NonlinearImager::
 set_texture_size(int index, int width, int height) {
   nassertv(index >= 0 && index < (int)_screens.size());
-  
+
   Screen &screen = _screens[index];
 
   screen._tex_width = width;

+ 1 - 0
panda/src/egg/eggNurbsSurface.h

@@ -77,6 +77,7 @@ PUBLISHED:
 
   virtual void write(ostream &out, int indent_level) const;
 
+public:
   Curves _curves_on_surface;
   Trims _trims;
 

+ 39 - 0
panda/src/event/pythonTask.I

@@ -12,3 +12,42 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: PythonTask::set_delay
+//       Access: Public
+//  Description: If None is passed, calls clear_delay, otherwise
+//               sets the delay time.  See AsyncTask::set_delay()
+//               and AsyncTask::clear_delay().
+////////////////////////////////////////////////////////////////////
+INLINE void PythonTask::
+set_delay(PyObject *delay) {
+  if (delay == Py_None) {
+    AsyncTask::clear_delay();
+    return;
+  }
+
+  PyObject *value = PyNumber_Float(delay);
+  if (value == NULL) {
+    return;
+  }
+
+  AsyncTask::set_delay(PyFloat_AS_DOUBLE(value));
+  Py_DECREF(value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PythonTask::get_delay
+//       Access: Public
+//  Description: Returns the delay time if set, None otherwise.
+//               See AsyncTask::has_delay() and AsyncTask::get_delay().
+////////////////////////////////////////////////////////////////////
+INLINE PyObject *PythonTask::
+get_delay() const {
+  if (AsyncTask::has_delay()) {
+    return PyFloat_FromDouble(AsyncTask::get_delay());
+  } else {
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+}

+ 101 - 79
panda/src/event/pythonTask.cxx

@@ -51,17 +51,11 @@ PythonTask(PyObject *function, const string &name) :
   set_upon_death(Py_None);
   set_owner(Py_None);
 
-  _dict = PyDict_New();
+  __dict__ = PyDict_New();
 
 #ifndef SIMPLE_THREADS
-  // Ensure that the Python threading system is initialized and ready
-  // to go.
+  // Ensure that the Python threading system is initialized and ready to go.
 #ifdef WITH_THREAD  // This symbol defined within Python.h
-
-#if PY_VERSION_HEX >= 0x03020000
-  Py_Initialize();
-#endif
-
   PyEval_InitThreads();
 #endif
 #endif
@@ -76,7 +70,7 @@ PythonTask::
 ~PythonTask() {
   Py_DECREF(_function);
   Py_DECREF(_args);
-  Py_DECREF(_dict);
+  Py_DECREF(__dict__);
   Py_XDECREF(_generator);
   Py_XDECREF(_owner);
   Py_XDECREF(_upon_death);
@@ -123,7 +117,7 @@ void PythonTask::
 set_args(PyObject *args, bool append_task) {
   Py_XDECREF(_args);
   _args = NULL;
-    
+
   if (args == Py_None) {
     // None means no arguments; create an empty tuple.
     _args = PyTuple_New(0);
@@ -254,53 +248,36 @@ get_owner() {
 //               arbitrary data to the Task object.
 ////////////////////////////////////////////////////////////////////
 int PythonTask::
-__setattr__(const string &attr_name, PyObject *v) {
+__setattr__(PyObject *self, PyObject *attr, PyObject *v) {
+  if (PyObject_GenericSetAttr(self, attr, v) == 0) {
+    return 0;
+  }
+
+  if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
+    return -1;
+  }
+
+  PyErr_Clear();
+
   if (task_cat.is_debug()) {
     PyObject *str = PyObject_Repr(v);
-    task_cat.debug() 
-      << *this << ": task." << attr_name << " = "
+    task_cat.debug()
+      << *this << ": task."
 #if PY_MAJOR_VERSION >= 3
+      << PyUnicode_AsUTF8(attr) << " = "
       << PyUnicode_AsUTF8(str) << "\n";
 #else
-      << PyString_AsString(str) << "\n"; 
+      << PyString_AsString(attr) << " = "
+      << PyString_AsString(str) << "\n";
 #endif
     Py_DECREF(str);
   }
 
-  if (attr_name == "delayTime") {
-    if (v == Py_None) {
-      clear_delay();
-    } else {
-      double delay = PyFloat_AsDouble(v);
-      if (!PyErr_Occurred()) {
-        set_delay(delay);
-      }
-    }
-
-  } else if (attr_name == "name") {
-#if PY_MAJOR_VERSION >= 3
-    char *name = PyUnicode_AsUTF8(v);
-#else
-    char *name = PyString_AsString(v);
-#endif
-    if (name != (char *)NULL) {
-      set_name(name);
-    }
-
-  } else if (attr_name == "id" || attr_name == "time" || 
-             attr_name == "frame" || attr_name == "wakeTime") {
-    nassert_raise("Cannot set constant value");
-    return true;
-
-  } else {
-    return PyDict_SetItemString(_dict, attr_name.c_str(), v);
-  }
-
-  return 0;
+  return PyDict_SetItem(__dict__, attr, v);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PythonTask::__setattr__
+//     Function: PythonTask::__delattr__
 //       Access: Published
 //  Description: Maps from an expression like "del task.attr_name".
 //               This is customized here so we can support some
@@ -309,8 +286,32 @@ __setattr__(const string &attr_name, PyObject *v) {
 //               arbitrary data to the Task object.
 ////////////////////////////////////////////////////////////////////
 int PythonTask::
-__setattr__(const string &attr_name) {
-  return PyDict_DelItemString(_dict, attr_name.c_str());
+__delattr__(PyObject *self, PyObject *attr) {
+  if (PyObject_GenericSetAttr(self, attr, NULL) == 0) {
+    return 0;
+  }
+
+  if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
+    return -1;
+  }
+
+  PyErr_Clear();
+
+  if (PyDict_DelItem(__dict__, attr) == -1) {
+    // PyDict_DelItem does not raise an exception.
+#if PY_MAJOR_VERSION < 3
+    PyErr_Format(PyExc_AttributeError,
+                 "'PythonTask' object has no attribute '%.400s'",
+                 PyString_AS_STRING(attr));
+#else
+    PyErr_Format(PyExc_AttributeError,
+                 "'PythonTask' object has no attribute '%U'",
+                 attr);
+#endif
+    return -1;
+  }
+
+  return 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -323,43 +324,64 @@ __setattr__(const string &attr_name) {
 //               arbitrary data to the Task object.
 ////////////////////////////////////////////////////////////////////
 PyObject *PythonTask::
-__getattr__(const string &attr_name) const {
-  if (attr_name == "time") {
-    return PyFloat_FromDouble(get_elapsed_time());
-
-  } else if (attr_name == "name") {
-#if PY_MAJOR_VERSION >= 3
-    return PyUnicode_FromString(get_name().c_str());
+__getattr__(PyObject *attr) const {
+  // Note that with the new Interrogate behavior, this method
+  // behaves more like the Python __getattr__ rather than being
+  // directly assigned to the tp_getattro slot (a la __getattribute__).
+  // So, we won't get here when the attribute has already been found
+  // via other methods.
+
+  PyObject *item = PyDict_GetItem(__dict__, attr);
+
+  if (item == NULL) {
+    // PyDict_GetItem does not raise an exception.
+#if PY_MAJOR_VERSION < 3
+    PyErr_Format(PyExc_AttributeError,
+                 "'PythonTask' object has no attribute '%.400s'",
+                 PyString_AS_STRING(attr));
 #else
-    return PyString_FromString(get_name().c_str());
+    PyErr_Format(PyExc_AttributeError,
+                 "'PythonTask' object has no attribute '%U'",
+                 attr);
 #endif
+    return NULL;
+  }
 
-  } else if (attr_name == "wakeTime") {
-    return PyFloat_FromDouble(get_wake_time());
-
-  } else if (attr_name == "delayTime") {
-    if (!has_delay()) {
-      Py_RETURN_NONE;
-    }
-    return PyFloat_FromDouble(get_delay());
-
-  } else if (attr_name == "frame") {
-#if PY_MAJOR_VERSION >= 3
-    return PyLong_FromLong(get_elapsed_frames());
-#else
-    return PyInt_FromLong(get_elapsed_frames());
-#endif
+  // PyDict_GetItem returns a borrowed reference.
+  Py_INCREF(item);
+  return item;
+}
 
-  } else if (attr_name == "id") {
-#if PY_MAJOR_VERSION >= 3
-    return PyLong_FromLong(_task_id);
-#else
-    return PyInt_FromLong(_task_id);
-#endif
+////////////////////////////////////////////////////////////////////
+//     Function: PythonTask::__traverse__
+//       Access: Published
+//  Description: Called by Python to implement cycle detection.
+////////////////////////////////////////////////////////////////////
+int PythonTask::
+__traverse__(visitproc visit, void *arg) {
+  Py_VISIT(_function);
+  Py_VISIT(_args);
+  Py_VISIT(_upon_death);
+  Py_VISIT(_owner);
+  Py_VISIT(__dict__);
+  Py_VISIT(_generator);
+  return 0;
+}
 
-  } else {
-    return PyMapping_GetItemString(_dict, (char *)attr_name.c_str());
-  }
+////////////////////////////////////////////////////////////////////
+//     Function: PythonTask::__clear__
+//       Access: Published
+//  Description: Called by Python to implement cycle breaking.
+////////////////////////////////////////////////////////////////////
+int PythonTask::
+__clear__() {
+  Py_CLEAR(_function);
+  Py_CLEAR(_args);
+  Py_CLEAR(_upon_death);
+  Py_CLEAR(_owner);
+  Py_CLEAR(__dict__);
+  Py_CLEAR(_generator);
+  return 0;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 43 - 4
panda/src/event/pythonTask.h

@@ -20,6 +20,8 @@
 #include "asyncTask.h"
 
 #ifdef HAVE_PYTHON
+#include "py_panda.h"
+
 ////////////////////////////////////////////////////////////////////
 //       Class : PythonTask
 // Description : This class exists to allow association of a Python
@@ -43,9 +45,47 @@ PUBLISHED:
   void set_owner(PyObject *owner);
   PyObject *get_owner();
 
-  int __setattr__(const string &attr_name, PyObject *v);
-  int __setattr__(const string &attr_name);
-  PyObject *__getattr__(const string &attr_name) const;
+  int __setattr__(PyObject *self, PyObject *attr, PyObject *v);
+  int __delattr__(PyObject *self, PyObject *attr);
+  PyObject *__getattr__(PyObject *attr) const;
+
+  int __traverse__(visitproc visit, void *arg);
+  int __clear__();
+
+  INLINE void set_delay(PyObject *delay);
+  INLINE PyObject *get_delay() const;
+
+PUBLISHED:
+  // The name of this task.
+  MAKE_PROPERTY(name, get_name, set_name);
+
+  // The amount of seconds that have elapsed since the task was
+  // started, according to the task manager's clock.
+  MAKE_PROPERTY(time, get_elapsed_time);
+
+  // If this task has been added to an AsyncTaskManager with a delay
+  // in effect, this contains the time at which the task is expected
+  // to awaken.  It has no meaning of the task has not yet been added
+  // to a queue, or if there was no delay in effect at the time the
+  // task was added.
+  //
+  // If the task's status is not S_sleeping, this contains 0.0.
+  MAKE_PROPERTY(wake_time, get_wake_time);
+
+  // The delay value that has been set on this task, if any, or None.
+  MAKE_PROPERTY(delay_time, get_delay, set_delay);
+
+  // The number of frames that have elapsed since the task was
+  // started, according to the task manager's clock.
+  MAKE_PROPERTY(frame, get_elapsed_frames);
+
+  // This is a number guaranteed to be unique for each different
+  // AsyncTask object in the universe.
+  MAKE_PROPERTY(id, get_task_id);
+
+  // This is a special variable to hold the instance dictionary in
+  // which custom variables may be stored.
+  PyObject *__dict__;
 
 protected:
   virtual bool is_runnable();
@@ -67,7 +107,6 @@ private:
   PyObject *_upon_death;
   PyObject *_owner;
   bool _registered_to_owner;
-  PyObject *_dict;
 
   PyObject *_generator;
 

+ 69 - 0
panda/src/express/filename_ext.cxx

@@ -0,0 +1,69 @@
+// Filename: filename_ext.cxx
+// Created by:  rdb (17Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "filename_ext.h"
+
+#ifdef HAVE_PYTHON
+////////////////////////////////////////////////////////////////////
+//     Function: Extension<Filename>::__reduce__
+//       Access: Published
+//  Description: This special Python method is implement to provide
+//               support for the pickle module.
+////////////////////////////////////////////////////////////////////
+PyObject *Extension<Filename>::
+__reduce__(PyObject *self) const {
+  // We should return at least a 2-tuple, (Class, (args)): the
+  // necessary class object whose constructor we should call
+  // (e.g. this), and the arguments necessary to reconstruct this
+  // object.
+  PyTypeObject *this_class = Py_TYPE(self);
+  if (this_class == NULL) {
+    return NULL;
+  }
+
+  PyObject *result = Py_BuildValue("(O(s))", this_class, _this->c_str());
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Extension<Filename>::scan_directory
+//       Access: Published
+//  Description: This variant on scan_directory returns a Python list
+//               of strings on success, or None on failure.
+////////////////////////////////////////////////////////////////////
+PyObject *Extension<Filename>::
+scan_directory() const {
+  vector_string contents;
+  if (!_this->scan_directory(contents)) {
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+
+  PyObject *result = PyList_New(contents.size());
+  for (size_t i = 0; i < contents.size(); ++i) {
+    const string &filename = contents[i];
+#if PY_MAJOR_VERSION >= 3
+    // This function expects UTF-8.
+    PyObject *str = PyUnicode_FromStringAndSize(filename.data(), filename.size());
+#else
+    PyObject *str = PyString_FromStringAndSize(filename.data(), filename.size());
+#endif
+    PyList_SET_ITEM(result, i, str);
+  }
+
+  return result;
+}
+#endif  // HAVE_PYTHON
+
+

+ 41 - 0
panda/src/express/filename_ext.h

@@ -0,0 +1,41 @@
+// Filename: filename_ext.h
+// Created by:  rdb (17Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef FILENAME_EXT_H
+#define FILENAME_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "filename.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<Filename>
+// Description : This class defines the extension methods for
+//               Filename, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<Filename> : public ExtensionBase<Filename> {
+public:
+  PyObject *__reduce__(PyObject *self) const;
+  PyObject *scan_directory() const;
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // FILENAME_EXT_H

+ 45 - 0
panda/src/express/globPattern_ext.cxx

@@ -0,0 +1,45 @@
+// Filename: globPattern_ext.cxx
+// Created by:  rdb (17Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "globPattern_ext.h"
+
+#ifdef HAVE_PYTHON
+
+////////////////////////////////////////////////////////////////////
+//     Function: Extension<GlobPattern>::match_files
+//       Access: Published
+//  Description: This variant on match_files returns a Python list
+//               of strings.
+////////////////////////////////////////////////////////////////////
+PyObject *Extension<GlobPattern>::
+match_files(const Filename &cwd) const {
+  vector_string contents;
+  _this->match_files(contents, cwd);
+
+  PyObject *result = PyList_New(contents.size());
+  for (size_t i = 0; i < contents.size(); ++i) {
+    const string &filename = contents[i];
+#if PY_MAJOR_VERSION >= 3
+    // This function expects UTF-8.
+    PyObject *str = PyUnicode_FromStringAndSize(filename.data(), filename.size());
+#else
+    PyObject *str = PyString_FromStringAndSize(filename.data(), filename.size());
+#endif
+    PyList_SET_ITEM(result, i, str);
+  }
+
+  return result;
+}
+
+#endif  // HAVE_PYTHON

+ 40 - 0
panda/src/express/globPattern_ext.h

@@ -0,0 +1,40 @@
+// Filename: globPattern_ext.h
+// Created by:  rdb (17Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GLOBPATTERN_EXT_H
+#define GLOBPATTERN_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "globPattern.h"
+#include "py_panda.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : Extension<GlobPattern>
+// Description : This class defines the extension methods for
+//               GlobPattern, which are called instead of
+//               any C++ methods with the same prototype.
+////////////////////////////////////////////////////////////////////
+template<>
+class Extension<GlobPattern> : public ExtensionBase<GlobPattern> {
+public:
+  PyObject *match_files(const Filename &cwd = Filename()) const;
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // GLOBPATTERN_EXT_H

+ 19 - 15
panda/src/express/multifile.h

@@ -84,27 +84,14 @@ PUBLISHED:
                         int compression_level);
 
 #ifdef HAVE_OPENSSL
-  class EXPCL_PANDAEXPRESS CertRecord {
-  public:
-    CertRecord(X509 *cert);
-    CertRecord(const CertRecord &copy);
-    ~CertRecord();
-    void operator = (const CertRecord &other);
-    X509 *_cert;
-  };
-  typedef pvector<CertRecord> CertChain;
-
-  bool add_signature(const Filename &certificate, 
+  bool add_signature(const Filename &certificate,
                      const Filename &chain,
                      const Filename &pkey,
                      const string &password = "");
-  bool add_signature(const Filename &composite, 
+  bool add_signature(const Filename &composite,
                      const string &password = "");
-  bool add_signature(X509 *certificate, STACK_OF(X509) *chain, EVP_PKEY *pkey);
-  bool add_signature(const CertChain &chain, EVP_PKEY *pkey);
 
   int get_num_signatures() const;
-  const CertChain &get_signature(int n) const;
   string get_signature_subject_name(int n) const;
   string get_signature_friendly_name(int n) const;
   string get_signature_public_key(int n) const;
@@ -152,6 +139,23 @@ PUBLISHED:
   INLINE const string &get_header_prefix() const;
 
 public:
+#ifdef HAVE_OPENSSL
+  class CertRecord {
+  public:
+    INLINE CertRecord(X509 *cert);
+    INLINE CertRecord(const CertRecord &copy);
+    INLINE ~CertRecord();
+    INLINE void operator = (const CertRecord &other);
+    X509 *_cert;
+  };
+  typedef pvector<CertRecord> CertChain;
+
+  bool add_signature(X509 *certificate, STACK_OF(X509) *chain, EVP_PKEY *pkey);
+  bool add_signature(const CertChain &chain, EVP_PKEY *pkey);
+
+  const CertChain &get_signature(int n) const;
+#endif  // HAVE_OPENSSL
+
   bool read_subfile(int index, string &result);
   bool read_subfile(int index, pvector<unsigned char> &result);
 

+ 3 - 0
panda/src/express/p3express_ext_composite.cxx

@@ -1,4 +1,7 @@
+#include "filename_ext.cxx"
+#include "globPattern_ext.cxx"
 #include "memoryUsagePointers_ext.cxx"
 #include "ramfile_ext.cxx"
 #include "streamReader_ext.cxx"
+#include "typeHandle_ext.cxx"
 #include "virtualFileSystem_ext.cxx"

+ 32 - 1
panda/src/express/pointerTo.I

@@ -109,6 +109,22 @@ operator T * () const {
   return (To *)(this->_void_ptr);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PointerTo::cheat
+//       Access: Public
+//  Description: Returns a reference to the underlying pointer.  This
+//               is a very unsafe method.  It's only used by some
+//               interrogate code.  If you think this method might be
+//               useful to you, you're probably wrong.
+//
+//               Promise me you won't use this, okay?
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE T *&PointerTo<T>::
+cheat() {
+  return (To *&)(this->_void_ptr);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PointerTo::p
 //       Access: Published
@@ -274,13 +290,28 @@ operator -> () const {
 //               don't care which way it goes because either will be
 //               correct.
 ////////////////////////////////////////////////////////////////////
-
 template<class T>
 INLINE ConstPointerTo<T>::
 operator const T * () const {
 return (To *)(this->_void_ptr);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ConstPointerTo::cheat
+//       Access: Public
+//  Description: Returns a reference to the underlying pointer.  This
+//               is a very unsafe method.  It's only used by some
+//               interrogate code.  If you think this method might be
+//               useful to you, you're probably wrong.
+//
+//               Promise me you won't use this, okay?
+////////////////////////////////////////////////////////////////////
+template<class T>
+INLINE const T *&ConstPointerTo<T>::
+cheat() {
+  return (const To *&)(this->_void_ptr);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ConstPointerTo::p
 //       Access: Published

部分文件因为文件数量过多而无法显示