From c178aba6394e3616fae5e7523018dba7bbe63816 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 19 Sep 2014 15:23:52 +0000 Subject: [PATCH] Add property support to interrogate (using MAKE_PROPERTY or using published members) --- contrib/src/ai/aiNode.h | 15 +-- dtool/src/cppparser/Sources.pp | 4 +- dtool/src/cppparser/cppBison.yxx | 35 +++++- dtool/src/cppparser/cppDeclaration.cxx | 11 +- dtool/src/cppparser/cppDeclaration.h | 7 +- dtool/src/cppparser/cppMakeProperty.cxx | 99 ++++++++++++++++ dtool/src/cppparser/cppMakeProperty.h | 51 ++++++++ dtool/src/cppparser/cppPreprocessor.cxx | 1 + dtool/src/cppparser/cppToken.cxx | 4 - .../src/cppparser/p3cppParser_composite1.cxx | 1 + dtool/src/dtoolbase/dtoolbase.h | 5 +- dtool/src/interrogate/functionRemap.cxx | 3 +- dtool/src/interrogate/interfaceMaker.cxx | 30 ++++- dtool/src/interrogate/interfaceMaker.h | 17 ++- dtool/src/interrogate/interfaceMakerC.cxx | 8 +- .../interfaceMakerPythonNative.cxx | 111 +++++++++++++++--- .../interrogate/interfaceMakerPythonNative.h | 2 +- .../interrogate/interfaceMakerPythonObj.cxx | 8 +- .../interfaceMakerPythonSimple.cxx | 12 +- dtool/src/interrogate/interrogateBuilder.cxx | 91 +++++++++++++- dtool/src/interrogate/interrogateBuilder.h | 6 + panda/src/egg/eggSwitchCondition.h | 2 +- 22 files changed, 459 insertions(+), 64 deletions(-) create mode 100644 dtool/src/cppparser/cppMakeProperty.cxx create mode 100644 dtool/src/cppparser/cppMakeProperty.h diff --git a/contrib/src/ai/aiNode.h b/contrib/src/ai/aiNode.h index b84fe56c0f..77f6036500 100644 --- a/contrib/src/ai/aiNode.h +++ b/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(); diff --git a/dtool/src/cppparser/Sources.pp b/dtool/src/cppparser/Sources.pp index 96bb4c7ff3..c5ff050468 100644 --- a/dtool/src/cppparser/Sources.pp +++ b/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 \ diff --git a/dtool/src/cppparser/cppBison.yxx b/dtool/src/cppparser/cppBison.yxx index 6d533f80d1..5a166ad8ae 100644 --- a/dtool/src/cppparser/cppBison.yxx +++ b/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 { } diff --git a/dtool/src/cppparser/cppDeclaration.cxx b/dtool/src/cppparser/cppDeclaration.cxx index fcc60903ca..c124e797c0 100644 --- a/dtool/src/cppparser/cppDeclaration.cxx +++ b/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 diff --git a/dtool/src/cppparser/cppDeclaration.h b/dtool/src/cppparser/cppDeclaration.h index f4f6474013..ba4c515142 100644 --- a/dtool/src/cppparser/cppDeclaration.h +++ b/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 - - - diff --git a/dtool/src/cppparser/cppMakeProperty.cxx b/dtool/src/cppparser/cppMakeProperty.cxx new file mode 100644 index 0000000000..d7d4fa9e67 --- /dev/null +++ b/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; +} diff --git a/dtool/src/cppparser/cppMakeProperty.h b/dtool/src/cppparser/cppMakeProperty.h new file mode 100644 index 0000000000..816f9d4958 --- /dev/null +++ b/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 diff --git a/dtool/src/cppparser/cppPreprocessor.cxx b/dtool/src/cppparser/cppPreprocessor.cxx index 9e0690e952..d0ed51f9b9 100644 --- a/dtool/src/cppparser/cppPreprocessor.cxx +++ b/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; diff --git a/dtool/src/cppparser/cppToken.cxx b/dtool/src/cppparser/cppToken.cxx index 75856748ea..9cb6102440 100644 --- a/dtool/src/cppparser/cppToken.cxx +++ b/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; diff --git a/dtool/src/cppparser/p3cppParser_composite1.cxx b/dtool/src/cppparser/p3cppParser_composite1.cxx index f14b966480..b8a7452e98 100644 --- a/dtool/src/cppparser/p3cppParser_composite1.cxx +++ b/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" diff --git a/dtool/src/dtoolbase/dtoolbase.h b/dtool/src/dtoolbase/dtoolbase.h index 160128e22e..8dfb7e2127 100644 --- a/dtool/src/dtoolbase/dtoolbase.h +++ b/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 diff --git a/dtool/src/interrogate/functionRemap.cxx b/dtool/src/interrogate/functionRemap.cxx index 94fcf5b00c..bc4da08534 100644 --- a/dtool/src/interrogate/functionRemap.cxx +++ b/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 = ""; diff --git a/dtool/src/interrogate/interfaceMaker.cxx b/dtool/src/interrogate/interfaceMaker.cxx index e392d25895..a5b62ac27b 100644 --- a/dtool/src/interrogate/interfaceMaker.cxx +++ b/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 &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()); diff --git a/dtool/src/interrogate/interfaceMaker.h b/dtool/src/interrogate/interfaceMaker.h index 189460d94b..6e94895ae7 100644 --- a/dtool/src/interrogate/interfaceMaker.h +++ b/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 FunctionsByIndex; typedef vector Functions; - Functions _functions; + FunctionsByIndex _functions; class MakeSeq { public: @@ -121,6 +123,16 @@ public: }; typedef vector MakeSeqs; + class Property { + public: + Property(const InterrogateElement &ielement); + + const InterrogateElement &_ielement; + Function *_getter; + Function *_setter; + }; + typedef vector 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, diff --git a/dtool/src/interrogate/interfaceMakerC.cxx b/dtool/src/interrogate/interfaceMakerC.cxx index 223f2ee08d..a1019241ed 100644 --- a/dtool/src/interrogate/interfaceMakerC.cxx +++ b/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); } diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 22c50809c6..eb25546d83 100755 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/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 > 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); - if (ielement.has_getter()) { - FunctionIndex func_index = ielement.get_getter(); - record_function(itype, func_index); - } + + Property *property = new Property(ielement); + if (ielement.has_setter()) { FunctionIndex func_index = ielement.get_setter(); - record_function(itype, func_index); + 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(); + Function *getter = record_function(itype, func_index); + if (is_function_legal(getter)) { + property->_getter = getter; + } + } + + if (property->_getter != NULL) { + object->_properties.push_back(property); + } else { + // No use exporting a property without a getter. + delete property; } } diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.h b/dtool/src/interrogate/interfaceMakerPythonNative.h index a7c20598db..7c7c35b317 100755 --- a/dtool/src/interrogate/interfaceMakerPythonNative.h +++ b/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 &remaps, string &expected_params, diff --git a/dtool/src/interrogate/interfaceMakerPythonObj.cxx b/dtool/src/interrogate/interfaceMakerPythonObj.cxx index f38497c299..497d506cdc 100644 --- a/dtool/src/interrogate/interfaceMakerPythonObj.cxx +++ b/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); } diff --git a/dtool/src/interrogate/interfaceMakerPythonSimple.cxx b/dtool/src/interrogate/interfaceMakerPythonSimple.cxx index b0e68c6683..6709c8e399 100644 --- a/dtool/src/interrogate/interfaceMakerPythonSimple.cxx +++ b/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); diff --git a/dtool/src/interrogate/interrogateBuilder.cxx b/dtool/src/interrogate/interrogateBuilder.cxx index 56ba78e345..a064c00590 100644 --- a/dtool/src/interrogate/interrogateBuilder.cxx +++ b/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); } } diff --git a/dtool/src/interrogate/interrogateBuilder.h b/dtool/src/interrogate/interrogateBuilder.h index 06b60f6fea..63a0814abb 100644 --- a/dtool/src/interrogate/interrogateBuilder.h +++ b/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 TypesByName; typedef map FunctionsByName; typedef map MakeSeqsByName; + typedef map PropertiesByName; TypesByName _types_by_name; FunctionsByName _functions_by_name; MakeSeqsByName _make_seqs_by_name; + PropertiesByName _properties_by_name; typedef map IncludeFiles; IncludeFiles _include_files; diff --git a/panda/src/egg/eggSwitchCondition.h b/panda/src/egg/eggSwitchCondition.h index 3ba07e4b07..5fcc2dc8de 100644 --- a/panda/src/egg/eggSwitchCondition.h +++ b/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; }