Explorar o código

Add property support to interrogate (using MAKE_PROPERTY or using published members)

rdb %!s(int64=11) %!d(string=hai) anos
pai
achega
c178aba639

+ 8 - 7
contrib/src/ai/aiNode.h

@@ -29,13 +29,7 @@
 //               on the mesh.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDAAI AINode {
-PUBLISHED:
-  // This variable specifies whether the node is an obtacle or not.
-  // Used for dynamic obstacle addition to the environment.
-  // obstacle = false
-  // navigational = true
-  bool _type;
-
+public:
   // This variable specifies the node status whether open, close
   // or neutral.
   // open = belongs to _open_list.
@@ -48,6 +42,12 @@ PUBLISHED:
   };
   Status _status;
 
+  // This variable specifies whether the node is an obtacle or not.
+  // Used for dynamic obstacle addition to the environment.
+  // obstacle = false
+  // navigational = true
+  bool _type;
+
   // The score is used to compute the traversal expense to nodes
   // when using A*.
   // _score = _cost + heuristic
@@ -76,6 +76,7 @@ PUBLISHED:
   // is written into navmesh.csv file.
   AINode *_next;
 
+PUBLISHED:
   AINode(int grid_x, int grid_y, LVecBase3f pos, float w, float l, float h);
   ~AINode();
 

+ 2 - 2
dtool/src/cppparser/Sources.pp

@@ -15,7 +15,7 @@
      cppExpressionParser.h cppExtensionType.h cppFile.h  \
      cppFunctionGroup.h cppFunctionType.h cppGlobals.h  \
      cppIdentifier.h cppInstance.h cppInstanceIdentifier.h  \
-     cppMakeSeq.h cppManifest.h \
+     cppMakeProperty.h cppMakeSeq.h cppManifest.h \
      cppNameComponent.h cppNamespace.h  \
      cppParameterList.h cppParser.h cppPointerType.h  \
      cppPreprocessor.h cppReferenceType.h cppScope.h  \
@@ -31,7 +31,7 @@
      cppExtensionType.cxx cppFile.cxx cppFunctionGroup.cxx  \
      cppFunctionType.cxx cppGlobals.cxx cppIdentifier.cxx  \
      cppInstance.cxx cppInstanceIdentifier.cxx \
-     cppMakeSeq.cxx cppManifest.cxx  \
+     cppMakeProperty.cxx cppMakeSeq.cxx cppManifest.cxx  \
      cppNameComponent.cxx cppNamespace.cxx cppParameterList.cxx  \
      cppParser.cxx cppPointerType.cxx cppPreprocessor.cxx  \
      cppReferenceType.cxx cppScope.cxx cppSimpleType.cxx  \

+ 32 - 3
dtool/src/cppparser/cppBison.yxx

@@ -14,6 +14,7 @@
 #include "cppEnumType.h"
 #include "cppFunctionType.h"
 #include "cppTBDType.h"
+#include "cppMakeProperty.h"
 #include "cppMakeSeq.h"
 #include "cppParameterList.h"
 #include "cppInstance.h"
@@ -234,7 +235,6 @@ pop_struct() {
 %token XOREQUAL
 %token LSHIFTEQUAL
 %token RSHIFTEQUAL
-%token TOKENPASTE
 
 %token KW_BEGIN_PUBLISH
 %token KW_BLOCKING
@@ -264,6 +264,7 @@ pop_struct() {
 %token KW_INT
 %token KW_LONG
 %token KW_LONGLONG
+%token KW_MAKE_PROPERTY
 %token KW_MAKE_SEQ
 %token KW_MUTABLE
 %token KW_NAMESPACE
@@ -475,7 +476,35 @@ declaration:
 {
   current_scope->set_current_vis(V_private);
 }
-	| KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
+        | KW_MAKE_PROPERTY '(' IDENTIFIER ',' IDENTIFIER ')' ';'
+{
+
+  CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
+  if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
+    yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @1);
+  }
+
+  CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(), NULL, current_scope, @1.file);
+  current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
+}
+        | KW_MAKE_PROPERTY '(' IDENTIFIER ',' IDENTIFIER ',' IDENTIFIER ')' ';'
+{
+  CPPDeclaration *getter = $5->find_symbol(current_scope, global_scope, current_lexer);
+  if (getter == (CPPDeclaration *)NULL || getter->get_subtype() != CPPDeclaration::ST_function_group) {
+    yyerror("Reference to non-existent or invalid getter: " + $5->get_fully_scoped_name(), @1);
+  }
+
+  CPPDeclaration *setter = $7->find_symbol(current_scope, global_scope, current_lexer);
+  if (setter == (CPPDeclaration *)NULL || setter->get_subtype() != CPPDeclaration::ST_function_group) {
+    yyerror("Reference to non-existent or invalid setter: " + $7->get_fully_scoped_name(), @1);
+  }
+
+  CPPMakeProperty *make_property = new CPPMakeProperty($3, getter->as_function_group(),
+                                                           setter->as_function_group(),
+                                                           current_scope, @1.file);
+  current_scope->add_declaration(make_property, global_scope, current_lexer, @1);
+}
+         | KW_MAKE_SEQ '(' name ',' name ',' name ')' ';'
 {
   CPPMakeSeq *make_seq = new CPPMakeSeq($3->get_simple_name(), $5->get_simple_name(), $7->get_simple_name(), @1.file);
   current_scope->add_declaration(make_seq, global_scope, current_lexer, @1);
@@ -2086,7 +2115,7 @@ element:
         | KW_SHORT | KW_SIGNED | KW_SIZEOF | KW_STATIC | KW_STATIC_CAST
         | KW_STRUCT | KW_THROW | KW_TRUE | KW_TRY | KW_TYPEDEF | KW_TYPENAME
         | KW_UNION | KW_UNSIGNED | KW_VIRTUAL | KW_VOID | KW_VOLATILE
-        | KW_WHILE | TOKENPASTE
+        | KW_WHILE
         | KW_OPERATOR
 {
 }

+ 10 - 1
dtool/src/cppparser/cppDeclaration.cxx

@@ -356,6 +356,16 @@ as_type_proxy() {
   return (CPPTypeProxy *)NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CPPDeclaration::as_make_property
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPMakeProperty *CPPDeclaration::
+as_make_property() {
+  return (CPPMakeProperty *)NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPDeclaration::as_make_seq
 //       Access: Public, Virtual
@@ -366,7 +376,6 @@ as_make_seq() {
   return (CPPMakeSeq *)NULL;
 }
 
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CPPDeclaration::is_equal
 //       Access: Protected, Virtual

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

@@ -47,6 +47,7 @@ class CPPExtensionType;
 class CPPStructType;
 class CPPEnumType;
 class CPPTypeProxy;
+class CPPMakeProperty;
 class CPPMakeSeq;
 class CPPClassTemplateParameter;
 class CPPTBDType;
@@ -69,6 +70,7 @@ public:
     ST_type,
     ST_namespace,
     ST_using,
+    ST_make_property,
     ST_make_seq,
 
     // Subtypes of CPPType
@@ -136,6 +138,7 @@ public:
   virtual CPPEnumType *as_enum_type();
   virtual CPPTBDType *as_tbd_type();
   virtual CPPTypeProxy *as_type_proxy();
+  virtual CPPMakeProperty *as_make_property();
   virtual CPPMakeSeq *as_make_seq();
 
   CPPVisibility _vis;
@@ -154,8 +157,4 @@ operator << (ostream &out, const CPPDeclaration &decl) {
   return out;
 }
 
-
 #endif
-
-
-

+ 99 - 0
dtool/src/cppparser/cppMakeProperty.cxx

@@ -0,0 +1,99 @@
+// Filename: cppMakeProperty.cxx
+// Created by:  rdb (18Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "cppMakeProperty.h"
+#include "cppFunctionGroup.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPMakeProperty::
+CPPMakeProperty(CPPIdentifier *ident,
+                CPPFunctionGroup *getter, CPPFunctionGroup *setter,
+                CPPScope *current_scope, const CPPFile &file) :
+  CPPDeclaration(file),
+  _ident(ident),
+  _getter(getter),
+  _setter(setter)
+{
+  _ident->_native_scope = current_scope;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::get_simple_name
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string CPPMakeProperty::
+get_simple_name() const {
+  return _ident->get_simple_name();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::get_local_name
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string CPPMakeProperty::
+get_local_name(CPPScope *scope) const {
+  return _ident->get_local_name(scope);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::get_fully_scoped_name
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+string CPPMakeProperty::
+get_fully_scoped_name() const {
+  return _ident->get_fully_scoped_name();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::output
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void CPPMakeProperty::
+output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
+  out << "__make_property(" << _ident->get_local_name(scope)
+      << ", " << _getter->_name;
+
+  if (_setter != NULL) {
+    out << ", " << _setter->_name;
+  }
+  out << ");";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::get_subtype
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPDeclaration::SubType CPPMakeProperty::
+get_subtype() const {
+  return ST_make_property;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CPPMakeProperty::as_make_property
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CPPMakeProperty *CPPMakeProperty::
+as_make_property() {
+  return this;
+}

+ 51 - 0
dtool/src/cppparser/cppMakeProperty.h

@@ -0,0 +1,51 @@
+// Filename: cppMakeProperty.h
+// Created by:  rdb (18Sep14)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 CPPMAKEPROPERTY_H
+#define CPPMAKEPROPERTY_H
+
+#include "dtoolbase.h"
+
+#include "cppDeclaration.h"
+
+///////////////////////////////////////////////////////////////////
+//       Class : CPPMakeProperty
+// Description : This is a MAKE_PROPERTY() declaration appearing
+//               within a class body.  It means to generate a property
+//               within Python, replacing (for instance)
+//               get_something()/set_something() with a synthetic
+//               'something' attribute.
+////////////////////////////////////////////////////////////////////
+class CPPMakeProperty : public CPPDeclaration {
+public:
+  CPPMakeProperty(CPPIdentifier *ident,
+                  CPPFunctionGroup *getter, CPPFunctionGroup *setter,
+                  CPPScope *current_scope, const CPPFile &file);
+
+  virtual string get_simple_name() const;
+  virtual string get_local_name(CPPScope *scope = NULL) const;
+  virtual string get_fully_scoped_name() const;
+
+  virtual void output(ostream &out, int indent_level, CPPScope *scope,
+                      bool complete) const;
+
+  virtual SubType get_subtype() const;
+  virtual CPPMakeProperty *as_make_property();
+
+  CPPIdentifier *_ident;
+  CPPFunctionGroup *_getter;
+  CPPFunctionGroup *_setter;
+};
+
+#endif

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

@@ -1987,6 +1987,7 @@ check_keyword(const string &name) {
   if (name == "inline") return KW_INLINE;
   if (name == "int") return KW_INT;
   if (name == "long") return KW_LONG;
+  if (name == "__make_property") return KW_MAKE_PROPERTY;
   if (name == "__make_seq") return KW_MAKE_SEQ;
   if (name == "mutable") return KW_MUTABLE;
   if (name == "namespace") return KW_NAMESPACE;

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

@@ -247,10 +247,6 @@ output(ostream &out) const {
     out << "RSHIFTEQUAL";
     break;
 
-  case TOKENPASTE:
-    out << "TOKENPASTE";
-    break;
-
   case KW_BOOL:
     out << "KW_BOOL";
     break;

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

@@ -4,6 +4,7 @@
 #include "cppCommentBlock.cxx"
 #include "cppConstType.cxx"
 #include "cppDeclaration.cxx"
+#include "cppMakeProperty.cxx"
 #include "cppMakeSeq.cxx"
 #include "cppParameterList.cxx"
 #include "cppParser.cxx"

+ 2 - 3
dtool/src/dtoolbase/dtoolbase.h

@@ -397,17 +397,16 @@
 #define BEGIN_PUBLISH __begin_publish
 #define END_PUBLISH __end_publish
 #define BLOCKING __blocking
+#define MAKE_PROPERTY(property_name, ...) __make_property(property_name, __VA_ARGS__)
 #define MAKE_SEQ(seq_name, num_name, element_name) __make_seq(seq_name, num_name, element_name)
 #undef USE_STL_ALLOCATOR  /* Don't try to parse these template classes in interrogate. */
 #define EXTENSION(x) __extension x
 #define EXTEND __extension
-#define EXT_FUNC(func) ::func()
-#define EXT_FUNC_ARGS(func, ...) ::func(__VA_ARGS__)
-#define CALL_EXT_FUNC(func, ...) ::func (__VA_ARGS__)
 #else
 #define BEGIN_PUBLISH
 #define END_PUBLISH
 #define BLOCKING
+#define MAKE_PROPERTY(property_name, ...)
 #define MAKE_SEQ(seq_name, num_name, element_name)
 #define EXTENSION(x)
 #define EXTEND

+ 2 - 1
dtool/src/interrogate/functionRemap.cxx

@@ -371,7 +371,8 @@ get_call_str(const string &container, const vector_string &pexprs) const {
     }
 
     call << " = ";
-    _parameters[0]._remap->pass_parameter(call, get_parameter_expr(_first_true_parameter, pexprs));
+    _parameters[_first_true_parameter]._remap->pass_parameter(call,
+                    get_parameter_expr(_first_true_parameter, pexprs));
 
   } else {
     const char *separator = "";

+ 25 - 5
dtool/src/interrogate/interfaceMaker.cxx

@@ -87,6 +87,19 @@ MakeSeq(const string &name, CPPMakeSeq *cpp_make_seq) :
 {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterfaceMaker::Property::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+InterfaceMaker::Property::
+Property(const InterrogateElement &ielement) :
+  _ielement(ielement),
+  _getter(NULL),
+  _setter(NULL)
+{
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterfaceMaker::Object::Constructor
 //       Access: Public
@@ -156,6 +169,8 @@ 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();
@@ -230,9 +245,9 @@ InterfaceMaker::
     Object *object = (*oi).second;
     delete object;
   }
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    delete (*fi);
+    delete (*fi).second;
   }
 }
 
@@ -501,9 +516,9 @@ wrap_global_functions() {
 ////////////////////////////////////////////////////////////////////
 void InterfaceMaker::
 get_function_remaps(vector<FunctionRemap *> &remaps) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     Function::Remaps::const_iterator ri;
     for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
       FunctionRemap *remap = (*ri);
@@ -617,12 +632,17 @@ get_unique_prefix() {
 ////////////////////////////////////////////////////////////////////
 InterfaceMaker::Function *InterfaceMaker::
 record_function(const InterrogateType &itype, FunctionIndex func_index) {
+  if (_functions.count(func_index)) {
+    // Already exists.
+    return _functions[func_index];
+  }
+
   InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
   const InterrogateFunction &ifunc = idb->get_function(func_index);
 
   string wrapper_name = get_wrapper_name(itype, ifunc, func_index);
   Function *func = new Function(wrapper_name, itype, ifunc);
-  _functions.push_back(func);
+  _functions[func_index] = func;
 
 //  printf(" Function Name = %s\n", ifunc.get_name().c_str());
 

+ 15 - 2
dtool/src/interrogate/interfaceMaker.h

@@ -29,8 +29,9 @@ class ParameterRemap;
 class CPPType;
 class CPPInstance;
 class InterrogateBuilder;
-class InterrogateType;
+class InterrogateElement;
 class InterrogateFunction;
+class InterrogateType;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : InterfaceMaker
@@ -107,8 +108,9 @@ public:
     int _flags;
     ArgsType _args_type;
   };
+  typedef map<FunctionIndex, Function *> FunctionsByIndex;
   typedef vector<Function *> Functions;
-  Functions _functions;
+  FunctionsByIndex _functions;
 
   class MakeSeq {
   public:
@@ -121,6 +123,16 @@ public:
   };
   typedef vector<MakeSeq *> MakeSeqs;
 
+  class Property {
+  public:
+    Property(const InterrogateElement &ielement);
+
+    const InterrogateElement &_ielement;
+    Function *_getter;
+    Function *_setter;
+  };
+  typedef vector<Property *> Properties;
+
   class Object {
   public:
     Object(const InterrogateType &itype);
@@ -133,6 +145,7 @@ public:
     Functions _constructors;
     Functions _methods;
     MakeSeqs _make_seqs;
+    Properties _properties;
 
     enum ProtocolTypes {
       PT_sequence         = 0x0001,

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

@@ -53,9 +53,9 @@ InterfaceMakerC::
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerC::
 write_prototypes(ostream &out,ostream *out_h) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_prototype_for(out, func);
   }
 
@@ -72,9 +72,9 @@ write_prototypes(ostream &out,ostream *out_h) {
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerC::
 write_functions(ostream &out) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_function_for(out, func);
   }
 

+ 95 - 14
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -817,9 +817,9 @@ write_functions(ostream &out) {
   out << "//********************************************************************\n";
   out << "//*** Functions for .. Global\n" ;
   out << "//********************************************************************\n";
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     if (!func->_itype.is_global() && is_function_legal(func)) {
       write_function_for_top(out, NULL, func);
     }
@@ -876,6 +876,23 @@ write_class_details(ostream &out, Object *obj) {
     }
   }
 
+  Properties::const_iterator pit;
+  for (pit = obj->_properties.begin(); pit != obj->_properties.end(); ++pit) {
+    Property *property = (*pit);
+    const InterrogateElement &ielem = property->_ielement;
+    bool coercion_attempted = false;
+
+    if (property->_getter != NULL) {
+      std::string fname = "PyObject *Dtool_" + ClassName + "_" + ielem.get_name() + "_Getter(PyObject *self, void *)";
+      write_function_for_name(out, obj, property->_getter, fname, true, coercion_attempted, AT_no_args, false, false);
+    }
+
+    if (property->_setter != NULL) {
+      std::string fname = "int Dtool_" + ClassName + "_" + ielem.get_name() + "_Setter(PyObject *self, PyObject *arg, void *)";
+      write_function_for_name(out, obj, property->_setter, fname, true, coercion_attempted, AT_single_arg, true, false);
+    }
+  }
+
   if (obj->_constructors.size() == 0) {
     out << "int Dtool_Init_" + ClassName + "(PyObject *self, PyObject *args, PyObject *kwds) {\n"
         << "  PyErr_SetString(PyExc_TypeError, \"cannot init constant class (" << cClassName << ")\");\n"
@@ -893,7 +910,7 @@ write_class_details(ostream &out, Object *obj) {
       Function *func = (*fi);
       std::string fname = "int Dtool_Init_" + ClassName + "(PyObject *self, PyObject *args, PyObject *kwds)";
 
-      write_function_for_name(out, obj, func, fname, true, coercion_attempted, AT_keyword_args, true);
+      write_function_for_name(out, obj, func, fname, true, coercion_attempted, AT_keyword_args, true, false);
     }
     if (coercion_attempted) {
       // If a coercion attempt was written into the above constructor,
@@ -903,7 +920,7 @@ write_class_details(ostream &out, Object *obj) {
         Function *func = (*fi);
         std::string fname = "int Dtool_InitNoCoerce_" + ClassName + "(PyObject *self, PyObject *args)";
 
-        write_function_for_name(out, obj, func, fname, false, coercion_attempted, AT_varargs, true);
+        write_function_for_name(out, obj, func, fname, false, coercion_attempted, AT_varargs, true, false);
       }
     } else {
       // Otherwise, since the above constructor didn't involve any
@@ -1114,9 +1131,9 @@ write_module_support(ostream &out, ostream *out_h, InterrogateModuleDef *def) {
   bool force_base_functions = true;
 
   out << "static PyMethodDef python_simple_funcs[] = {\n";
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     if (!func->_itype.is_global() && is_function_legal(func)) {
       string name1 = methodNameFromCppName(func, "", false);
       string name2 = methodNameFromCppName(func, "", true);
@@ -2078,6 +2095,44 @@ write_module_class(ostream &out, Object *obj) {
     out << "}\n\n";
   }
 
+  if (obj->_properties.size() > 0) {
+    // Write out the array of properties, telling Python which getter and setter
+    // to call when they are assigned or queried in Python code.
+    out << "PyGetSetDef Dtool_Properties_" << ClassName << "[] = {\n";
+
+    Properties::const_iterator pit;
+    for (pit = obj->_properties.begin(); pit != obj->_properties.end(); ++pit) {
+      Property *property = (*pit);
+      const InterrogateElement &ielem = property->_ielement;
+      if (property->_getter == NULL || !is_function_legal(property->_getter)) {
+        continue;
+      }
+
+      out << "  {(char *)\"" << ielem.get_name() << "\","
+          << " &Dtool_" << ClassName << "_" << ielem.get_name() << "_Getter,";
+
+      if (property->_setter == NULL || !is_function_legal(property->_setter)) {
+        out << " NULL,";
+      } else {
+        out << " &Dtool_" << ClassName << "_" << ielem.get_name() << "_Setter,";
+      }
+
+      if (ielem.has_comment()) {
+        out << "(char *)\n";
+        output_quoted(out, 4, ielem.get_comment());
+        out << ",\n    ";
+      } else {
+        out << " NULL, ";
+      }
+
+      // Extra void* argument; we don't make use of it.
+      out << "NULL},\n";
+    }
+
+    out << "  {NULL},\n";
+    out << "};\n\n";
+  }
+
   out << "void Dtool_PyModuleClassInit_" << ClassName << "(PyObject *module) {\n";
   out << "  static bool initdone = false;\n";
   out << "  if (!initdone) {\n";
@@ -2190,6 +2245,11 @@ write_module_class(ostream &out, Object *obj) {
     out << "    Dtool_" << ClassName << ".As_PyTypeObject().tp_str = &Dtool_Repr_" << ClassName << ";\n";
   }
 
+  if (obj->_properties.size() > 0) {
+    // GetSet descriptor slots.
+    out << "    Dtool_" << ClassName << ".As_PyTypeObject().tp_getset = Dtool_Properties_" << ClassName << ";\n";
+  }
+
   int num_nested = obj->_itype.number_of_nested_types();
   for (int ni = 0; ni < num_nested; ni++) {
     TypeIndex nested_index = obj->_itype.get_nested_type(ni);
@@ -2395,7 +2455,7 @@ write_function_for_top(ostream &out, InterfaceMaker::Object *obj, InterfaceMaker
   fname += ")";
 
   bool coercion_attempted = false;
-  write_function_for_name(out, obj, func, fname, true, coercion_attempted, func->_args_type, false);
+  write_function_for_name(out, obj, func, fname, true, coercion_attempted, func->_args_type, false, true);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2407,7 +2467,7 @@ void InterfaceMakerPythonNative::
 write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMaker::Function *func,
                         const std::string &function_name,
                         bool coercion_allowed, bool &coercion_attempted,
-                        ArgsType args_type, bool return_int) {
+                        ArgsType args_type, bool return_int, bool write_comment) {
   ostringstream out;
 
   std::map<int, std::set<FunctionRemap *> > MapSets;
@@ -2462,7 +2522,11 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
       // Other functions should raise an exception if the this
       // pointer isn't set or is the wrong type.
       out << "    PyErr_SetString(PyExc_AttributeError, \"C++ object is not yet constructed, or already destructed.\");\n";
-      out << "    return NULL;\n";
+      if (return_int) {
+        out << "    return -1;\n";
+      } else {
+        out << "    return NULL;\n";
+      }
     }
     out << "  }\n";
   }
@@ -2639,7 +2703,7 @@ write_function_for_name(ostream &out1, InterfaceMaker::Object *obj, InterfaceMak
     FunctionComment = FunctionComment1 + "\n" + FunctionComment;
   }
 
-  if (!return_int) {
+  if (write_comment) {
     // Write out the function doc string.  We only do this if it is
     // not a constructor, since we don't have a place to put the
     // constructor doc string.
@@ -4004,13 +4068,30 @@ record_object(TypeIndex type_index) {
   for (int ei = 0; ei < num_elements; ei++) {
     ElementIndex element_index = itype.get_element(ei);
     const InterrogateElement &ielement = idb->get_element(element_index);
+
+    Property *property = new Property(ielement);
+
+    if (ielement.has_setter()) {
+      FunctionIndex func_index = ielement.get_setter();
+      Function *setter = record_function(itype, func_index);
+      if (is_function_legal(setter)) {
+        property->_setter = setter;
+      }
+    }
+
     if (ielement.has_getter()) {
       FunctionIndex func_index = ielement.get_getter();
-      record_function(itype, func_index);
+      Function *getter = record_function(itype, func_index);
+      if (is_function_legal(getter)) {
+        property->_getter = getter;
+      }
     }
-    if (ielement.has_setter()) {
-      FunctionIndex func_index = ielement.get_setter();
-      record_function(itype, func_index);
+
+    if (property->_getter != NULL) {
+      object->_properties.push_back(property);
+    } else {
+      // No use exporting a property without a getter.
+      delete property;
     }
   }
 

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

@@ -95,7 +95,7 @@ private:
   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);
+                               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,

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

@@ -55,9 +55,9 @@ InterfaceMakerPythonObj::
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonObj::
 write_prototypes(ostream &out, ostream *out_h) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_prototype_for(out, func);
   }
 
@@ -74,9 +74,9 @@ write_prototypes(ostream &out, ostream *out_h) {
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonObj::
 write_functions(ostream &out) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_function_for(out, func);
   }
 

+ 6 - 6
dtool/src/interrogate/interfaceMakerPythonSimple.cxx

@@ -53,9 +53,9 @@ InterfaceMakerPythonSimple::
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonSimple::
 write_prototypes(ostream &out,ostream *out_h) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_prototype_for(out, func);
   }
 
@@ -72,9 +72,9 @@ write_prototypes(ostream &out,ostream *out_h) {
 ////////////////////////////////////////////////////////////////////
 void InterfaceMakerPythonSimple::
 write_functions(ostream &out) {
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     write_function_for(out, func);
   }
 
@@ -93,9 +93,9 @@ write_module(ostream &out,ostream *out_h, InterrogateModuleDef *def) {
 
   out << "static PyMethodDef python_simple_funcs[] = {\n";
 
-  Functions::iterator fi;
+  FunctionsByIndex::iterator fi;
   for (fi = _functions.begin(); fi != _functions.end(); ++fi) {
-    Function *func = (*fi);
+    Function *func = (*fi).second;
     Function::Remaps::const_iterator ri;
     for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) {
       FunctionRemap *remap = (*ri);

+ 90 - 1
dtool/src/interrogate/interrogateBuilder.cxx

@@ -44,6 +44,7 @@
 #include "cppTypeDeclaration.h"
 #include "cppEnumType.h"
 #include "cppCommentBlock.h"
+#include "cppMakeProperty.h"
 #include "cppMakeSeq.h"
 #include "pnotify.h"
 
@@ -1357,7 +1358,7 @@ scan_element(CPPInstance *element, CPPStructType *struct_type,
   ielement._name = element->get_local_name(scope);
   ielement._scoped_name = descope(element->get_local_name(&parser));
 
-  // See if there happens to be a comment before the element.
+  // See if there happens to be a comment before the MAKE_PROPERTY macro.
   if (element->_leading_comment != (CPPCommentBlock *)NULL) {
     ielement._comment = trim_blanks(element->_leading_comment->_comment);
   }
@@ -1774,6 +1775,90 @@ get_function(CPPInstance *function, string description,
   return index;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InterrogateBuilder::get_make_property
+//       Access: Private
+//  Description: Adds the indicated make_property to the database,
+//               if it is not already present.  In either case,
+//               returns the MakeSeqIndex of the make_seq within the
+//               database.
+////////////////////////////////////////////////////////////////////
+ElementIndex InterrogateBuilder::
+get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type) {
+  string property_name = make_property->get_local_name(&parser);
+
+  // First, check to see if it's already there.
+  PropertiesByName::const_iterator tni =
+    _properties_by_name.find(property_name);
+  if (tni != _properties_by_name.end()) {
+    ElementIndex index = (*tni).second;
+    return index;
+  }
+
+  // Find the getter so we can get its return type.
+  CPPInstance *getter = NULL;
+  CPPType *return_type = NULL;
+
+  CPPFunctionGroup *fgroup = make_property->_getter;
+  CPPFunctionGroup::Instances::const_iterator fi;
+  for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
+    CPPInstance *function = (*fi);
+    CPPFunctionType *ftype =
+      function->_type->as_function_type();
+    if (ftype != NULL && ftype->_parameters->_parameters.size() == 0) {
+      getter = function;
+      return_type = ftype->_return_type;
+
+      // The return type of the non-const method probably better represents
+      // the type of the property we are creating.
+      if ((ftype->_flags & CPPFunctionType::F_const_method) == 0) {
+        break;
+      }
+    }
+  }
+
+  if (getter == NULL || return_type == NULL) {
+    cerr << "No instance of getter '"
+         << make_property->_getter->_name << "' is suitable!\n";
+    return 0;
+  }
+
+  InterrogateDatabase *idb = InterrogateDatabase::get_ptr();
+  // It isn't here, so we'll have to define it.
+  ElementIndex index = idb->get_next_index();
+  _properties_by_name[property_name] = index;
+
+  InterrogateElement iproperty;
+  iproperty._name = make_property->get_simple_name();
+  iproperty._scoped_name = descope(make_property->get_local_name(&parser));
+
+  iproperty._type = get_type(return_type, false);
+
+  iproperty._flags |= InterrogateElement::F_has_getter;
+  iproperty._getter = get_function(getter, "", struct_type,
+                                   struct_type->get_scope(), 0);
+
+  // See if there happens to be a comment before the element.
+  if (make_property->_leading_comment != (CPPCommentBlock *)NULL) {
+    iproperty._comment = trim_blanks(make_property->_leading_comment->_comment);
+  }
+
+  // Now look for setters.
+  fgroup = make_property->_setter;
+  if (fgroup != NULL) {
+    for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
+      CPPInstance *function = (*fi);
+      iproperty._flags |= InterrogateElement::F_has_setter;
+      iproperty._setter = get_function(function, "", struct_type,
+                                       struct_type->get_scope(), 0);
+    }
+  }
+
+  idb->add_element(index, iproperty);
+
+  return index;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: InterrogateBuilder::get_make_seq
 //       Access: Private
@@ -2285,6 +2370,10 @@ define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
         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);
     }
   }
 

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

@@ -38,6 +38,7 @@ class CPPScope;
 class CPPIdentifier;
 class CPPNameComponent;
 class CPPManifest;
+class CPPMakeProperty;
 class CPPMakeSeq;
 class InterrogateType;
 class InterrogateFunction;
@@ -108,6 +109,9 @@ public:
                CPPStructType *struct_type, CPPScope *scope,
                int flags, const string &expression = string());
 
+  ElementIndex
+  get_make_property(CPPMakeProperty *make_property, CPPStructType *struct_type);
+
   MakeSeqIndex
   get_make_seq(CPPMakeSeq *make_seq, CPPStructType *struct_type);
 
@@ -132,10 +136,12 @@ public:
   typedef map<string, TypeIndex> TypesByName;
   typedef map<string, FunctionIndex> FunctionsByName;
   typedef map<string, MakeSeqIndex> MakeSeqsByName;
+  typedef map<string, ElementIndex> PropertiesByName;
 
   TypesByName _types_by_name;
   FunctionsByName _functions_by_name;
   MakeSeqsByName _make_seqs_by_name;
+  PropertiesByName _properties_by_name;
 
   typedef map<string, char> IncludeFiles;
   IncludeFiles _include_files;

+ 1 - 1
panda/src/egg/eggSwitchCondition.h

@@ -73,11 +73,11 @@ PUBLISHED:
 
   virtual void transform(const LMatrix4d &mat);
 
+public:
   double _switch_in, _switch_out, _fade;
   LPoint3d _center;
 
 public:
-
   static TypeHandle get_class_type() {
     return _type_handle;
   }